FORM BANNER
FORM BANNER

Fase I : Contexto

Lecturas Sugeridas

What is Exploratory Data Analysis?

https://www.ibm.com/topics/exploratory-data-analysis

What is Descriptive Analytics? 5 Examples

https://online.hbs.edu/blog/post/descriptive-analytics

Nearshoring will Make Mexico ’The Motor” of US Electric Vehicle

Industry https://www.bloomberglinea.com/english/nearshoring-will-make-mexico-the-motor-of-us-electric-vehicle-industry/

Nearshoring: Los Retos y Oportunidades que tiene para México en

  1. https://conecta.tec.mx/es/noticias/nacional/emprendedores/nearshoring-los-retos-y-oportunidades-que-tiene-para-mexico-en-2024#:~:text=El%20nearshoring%20es%20una%20estrategia,en%20un%20pa%C3%ADs%20cercano%20geogr%C3%A1ficamente

Librerías necesarias

library(imputeTS) # Rellenar datos faltantes
library(xts) # Manipulación de series temporales
library(zoo) # Sistemas de series temporales
library(tseries) # Análisis de series temporales
library(stats) # Funciones estadísticas básicas
library(forecast) # Predicción de series temporales
library(astsa) # Análisis de series temporales aplicado
library(corrplot) # Visualización de matrices de correlación
library(wordcloud) # Crear nubes de palabras
library(tidytext) # Análisis de texto con tidy data
library(AER) # Análisis econométrico con R
library(vars) # Modelos VAR y SVAR
library(dynlm) # Modelos lineales dinámicos
library(mFilter) # Filtros para series temporales
library(TSstudio) # Herramientas interactivas series temporales
library(tidyverse) # Colección de paquetes de datos tidy
library(sarima) # Modelos SARIMA
library(readr) # Leer archivos planos
library(readxl) # Leer archivos Excel
library(heatmaply) # Heatmaps interactivos
library(dplyr) # Manipulación de datos
library(ggplot2) # Sistema de gráficos
library(psych) # Procedimientos psicométricos
library(tidyr) # Reorganización de datos
library(readtext) # Leer archivos de texto
library(syuzhet) # Análisis de sentimientos
library(RColorBrewer) # Paletas de colores
library(tm) # Minería de texto
library(caret) # Entrenamiento de modelos predictivos
library(MASS) # Métodos estadísticos adicionales
library(rpart) # Modelos de partición recursiva
library(rpart.plot) # Gráficos para rpart
library(party) # Modelos basados en árboles
library(gmodels) # Herramientas de modelado
library(knitr) # Reportes dinámicos
library(cluster) # Métodos de agrupamiento
library(e1071) # Misc funciones SVM
library(pROC) # Curvas ROC
library(ISLR) # Data sets para aprendizaje estadístico
library(gridExtra) # Disposición de múltiples gráficos
library(car) # Regresión y Anova con R
library(DataExplorer) # Automatizar análisis exploratorio
library(randomForest) # Clasificación con random forest
library(class) # k-vecinos más cercanos
library(factoextra) # Visualización de resultados de clustering
library(purrr) # Programación funcional
library(viridis) # Paletas de colores para gráficos
library(scales) # Escalado de gráficos
library(lubridate) # Manipulación de fechas y horas
library(patchwork) # Combinar ggplot2 plots
library(janeaustenr) # Textos de Jane Austen
library(reshape2) # Reestructurar datos
library(tmap) # Crear mapas
library(sf) # Manipulación de datos geoespaciales

Bases de Datos

setwd("../databases")

form_satisfaccion <- read_excel("form/Encuesta_Datos_FORM_Fall2023.xlsx")
form_bajas = read_xlsx("form/temporary/BDD_FORM_BAJAS-2023.xlsx")
cp_nl <- st_read("geo_reference__nl/CP_NL")
## Reading layer `CP_19NL_v10' from data source 
##   `/Users/daviddrums180/Tec/Case_Study_Form/databases/geo_reference__nl/CP_NL' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 1338 features and 1 field
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 2578831 ymin: 1238179 xmax: 2858006 ymax: 1749577
## Projected CRS: Lambert_Conformal_Conic
exp_vehiculos = read_csv("industry_autos_mx/exportacion_vehiculos_mx.csv")
ventas_vehiculos = read_csv("industry_autos_mx/mx_venta_vehiculos.csv")
exp_vehiculos_total = read_excel("industry_autos_mx/exportacion_vehiculos.xlsx")

form_rh = read_csv("form/Datos_FORM_RH_FJ2024.csv")
form_ventas_detalle = read_excel("form/Datos_FORM_Ventas_FJ2024.xlsx")

Introducción

Preguntas de Reflexión

¿Qué es un análisis exploratorio de los datos?

El análisis exploratorio de los datos o EDA es un proceso analitico inicial en el analisis de conjuntos de datos que permite obtener una comprensión de las características fundamentales de los datos.

Esto se puede hacer mediante resúmenes estadísticos, medidas descriptivas, visualización de datos, y la identificación de patrones o anomalías dentro del conjunto de datos con matrices de correlación o scatter plots. Su objetivo principal es explorar y entender la naturaleza de los datos para informar las etapas posteriores del análisis.

¿Cómo contribuye el análisis exploratorio de los datos a mejorar el proceso y los resultados de analítica descriptiva?

El análisis exploratorio de los datos contribuye significativamente a mejorar el proceso y los resultados de la analítica descriptiva de varias maneras. Primero, ayuda a identificar las tendencias, correlaciones y patrones ocultos que pueden ser importantes para la comprensión de los datos. Esto permite formular hipótesis más precisas y dirigir el análisis descriptivo y posterior (predictivo o prescriptivo) de manera más efectiva.

Segundo, al descubrir datos atípicos o anomalías, el EDA asegura la calidad y la precisión de los datos antes de proceder con análisis más complejos, así como identificar la necesidad de transformaciónes necesarias previas a realizar el análisis Finalmente, facilita la selección de las técnicas estadísticas o modelos de datos más adecuados al revelar la estructura y distribución de los datos, lo que conduce a insights más relevantes y a la toma de decisiones basada en datos.

Antecedentes de la Empresa FORM

La empresa FORM, con sede en México, se ha destacado en el desarrollo de innovaciones en el empaque de autopartes, enfocándose en soluciones que permiten reducir el espacio necesario para almacenamiento y generando ahorros en logística. Han introducido un producto patentado globalmente que aumenta la capacidad de empaque y reduce significativamente el uso de materia prima, lo cual también tiene un impacto positivo en el medio ambiente.

Desde su fundación en 2011, FORM ha crecido significativamente, comenzando con un solo cliente y seis empleados, y expandiéndose a más de 150 colaboradores y atendiendo a más de 15 clientes automotrices. Entre sus clientes se encuentran nombres prominentes como Denso, Magna, International Automotive Components y Varroc Lighting Systems.

La especialización de FORM en empaques para autopartes delicadas y costosas la ha llevado a ser proveedor de armadoras de prestigio como Tesla, BMW y Mercedes Benz. Ofrecen soluciones personalizadas que aseguran la protección y la integridad de las autopartes durante su transporte, lo que es crucial para piezas de acabado delicado o espejo.

Con una planta en Apodaca, Nuevo León, la empresa ha establecido un área especializada para empaques termoformados, esenciales para el transporte de piezas electrónicas y otras autopartes sensibles que requieren cuidado especial para evitar daños durante el tránsito.

La filosofía de FORM de reducir el espacio de almacenamiento, la mano de obra para la administración y el armado de empaques, junto con la protección del producto, se alinea con la demanda creciente de la industria automotriz por eficiencia y sostenibilidad en las cadenas de suministro.

Las innovaciones de FORM y su enfoque en la sostenibilidad y eficiencia reflejan un compromiso con la mejora continua y la adaptación a las necesidades cambiantes del mercado automotriz, lo que les ha permitido mantenerse competitivos y relevantes en un sector en constante evolución.

Misión

Transformar nuestro entorno y resolver retos industriales de nuestros clientes a través de la colaboración, provocando nuevas oportunidades que potencian nuestro modelo de negocio, para alcanzar nuestros ideales.

Visión

En 2033 seremos una de las cinco mejores compañías de México que generan valor dentro de la cadena de suministro de las industrias que más valoran la forma en la que se protegen y trasladan las cosas.

Objetivo Estratégico

“Ahora estamos volteando a los Estados Unidos, y ahora con la posibilidad de que Tesla llegue a Nuevo León, con mayor sentido volteamos hacia allá. Si todos nuestros clientes son automotrices e internacionales por qué no proveerlos en Estados Unidos, estamos trabajando fuerte para lograrlo”. - Felipe Flores García

Contexto de la Industria

Análisis de la Industria (cartón, autopartes, automotriz)

Para el caso de México y E.U.A. (incluir 3-5 gráficos usando R*) usando fuentes de datos secundarias

El mercado automotriz en México constituye un sector vital para la economía del país, no solo por su significativa contribución al Producto Interno Bruto (PIB) sino también por su papel en la creación de empleos y en el fomento de la innovación tecnológica. Una faceta crucial de esta industria es el mercado de autopartes, que se erige como un pilar fundamental para la operatividad y el desarrollo de la industria automotriz en su conjunto. Este segmento incluye desde la fabricación de componentes esenciales del vehículo hasta sistemas avanzados que mejoran la seguridad, el rendimiento y la comodidad.

La interacción entre los fabricantes de automóviles y los proveedores de autopartes es intrínseca al ciclo de vida del producto automotriz, afectando directamente la cadena de suministro, la innovación en el diseño de productos y, en última instancia, la competitividad en el mercado global. Además, el mercado de autopartes en México se ve influenciado por factores como las regulaciones gubernamentales, los tratados de libre comercio, las tendencias de consumo y los avances tecnológicos, lo que lo convierte en un campo de estudio dinámico y complejo.

Exploración de Exportación de Vehículos

Para profundizar en el entendimiento de esta industria, se realizará un análisis exhaustivo utilizando diversas bases de datos recopiladas de múltiples fuentes. Este análisis buscará identificar tendencias, desafíos y oportunidades dentro del mercado de autopartes, así como su interconexión con la industria automotriz en general. Se examinarán aspectos como la evolución de la demanda de autopartes, la cadena de valor, el impacto de la tecnología en la producción y el diseño de autopartes, así como las estrategias adoptadas por las empresas para navegar en un entorno económico y regulatorio en constante cambio.

Analisis de Exportación de Vehiculos

mx_vehicle_exports <- read_excel("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_autos_mx/exportacion_vehiculos.xlsx")

mx_vehicle_exports_summary <- mx_vehicle_exports %>%
  group_by(Año, Segmento) %>%
  summarise(Cantidad_Total = sum(Cantidad, na.rm = TRUE))

# Definir la paleta de colores personalizada
colores <- c("#2D3250", "#435585", "#7077A1", "#F6B17A", "#9EC8B9", "#BE3144")

# Asegurarse de que hay suficientes colores para los segmentos
# Repetir la paleta si hay más segmentos que colores
n_segmentos <- length(unique(mx_vehicle_exports_summary$Segmento))
if (n_segmentos > length(colores)) {
  colores <- rep(colores, length.out = n_segmentos)
}

# Gráfico de líneas con la paleta de colores personalizada
ggplot(mx_vehicle_exports_summary, aes(x = Año, y = Cantidad_Total, color = Segmento, group = Segmento)) + 
  geom_line() + # Dibuja líneas
  geom_point() + # Añade puntos en cada dato
  scale_color_manual(values = colores) + # Usa la paleta de colores definida
  theme_minimal() + # Usa un tema minimalista
  labs(title = "Evolución de la Exportación de Segmento de Vehículo a lo Largo de los Años",
       x = "Año",
       y = "Cantidad Total") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

1. Crecimiento de SUVs: - La exportación de SUVs ha visto un crecimiento significativo hasta 2018, seguido de una disminución. Esto podría indicar cambios en la preferencia del consumidor o en la dinámica del mercado. FORM puede aprovechar esta tendencia ofreciendo soluciones de empaque personalizadas para este segmento, que parece tener una alta variabilidad en la demanda.

2. Volatilidad en Segmento de Lujo: - El segmento de lujo muestra volatilidad con un pico marcado alrededor de 2018. Esto puede abrir oportunidades para FORM en términos de proporcionar empaques de alta calidad que coincidan con las expectativas de los fabricantes de vehículos de lujo y sus consumidores.

3. Caída General Post-2018: - Después de 2018, todos los segmentos excepto los subcompactos muestran una caída, lo que podría deberse a factores económicos globales, políticas comerciales o la pandemia. FORM debe estar atento a estos factores externos que afectan la demanda de sus productos.

4. Beneficios Potenciales para FORM: - El análisis de estas tendencias es vital para FORM, ya que proporciona información sobre qué segmentos podrían requerir más empaques en el futuro. Esto puede guiar sus decisiones de inversión y estrategias de producción para los próximos años.

5. Modelo Predictivo para la Demanda: - Utilizar estos datos para desarrollar un modelo predictivo podría ayudar a FORM a anticiparse a las necesidades del mercado. Herramientas de análisis predictivo, como el Machine Learning, podrían usarse para prever la demanda futura basándose en las tendencias históricas y factores externos.

# Sumarizar la cantidad total por País destino y obtener los top 5
top_paises_destino <- mx_vehicle_exports %>%
  group_by(`País destino`) %>%
  summarise(Cantidad_Total = sum(Cantidad, na.rm = TRUE)) %>%
  arrange(desc(Cantidad_Total)) %>%
  slice_head(n = 5)

# Filtrar el dataframe original para tener solo los top 5 País destino
mx_vehicle_exports_top5 <- mx_vehicle_exports %>%
  filter(`País destino` %in% top_paises_destino$`País destino`)

# Código para un box plot de la variable Cantidad por los top 5 País destino
ggplot(mx_vehicle_exports_top5, aes(x = `País destino`, y = Cantidad)) + 
  geom_boxplot() +  
  theme_minimal() + 
  labs(title = "Box Plot de Cantidad por Top 5 País Destino",
       x = "País Destino",
       y = "Cantidad") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5))

1. Dominancia de Estados Unidos: - Estados Unidos muestra una mediana y un rango intercuartílico superior a otros destinos, lo cual indica que es el principal mercado para la exportación. FORM puede centrarse en aumentar la capacidad de producción y mejorar las soluciones logísticas para satisfacer la alta demanda de empaques en este mercado.

2. Variabilidad en ‘No Especificado’: - La categoría ‘No Especificado’ tiene una alta variabilidad y valores atípicos, lo que podría indicar oportunidades no exploradas o datos incompletos. FORM podría investigar estos casos para identificar posibles nuevos mercados o mejorar la precisión en la recopilación de datos.

3. Consistencia en Alemania y Brasil: - Alemania y Brasil muestran una menor dispersión y consistencia en los envíos, lo que podría reflejar mercados establecidos con demandas predecibles. FORM puede utilizar esta información para optimizar inventarios y prever recursos de producción.

4. Beneficios del Análisis para FORM: - Analizar esta distribución de exportaciones podría ayudar a FORM a entender mejor la variabilidad y la consistencia en la demanda entre diferentes mercados. Esta información puede ser crítica para optimizar la cadena de suministro y poder desarrollar un modelo que ayude a predecir y controlar los niveles de inventario necesarios.

5. Modelo Predictivo para la Demanda: - Desarrollar un modelo predictivo basado en estos datos permitiría a FORM anticipar la demanda y ajustar la producción de forma proactiva. La utilización de técnicas estadísticas como la regresión, conjuntamente con algoritmos de machine learning, podría proporcionar estimaciones precisas de la demanda futura basándose en patrones históricos y tendencias actuales.

Exploración a Mercado de Autopartes

A través de este enfoque analítico, se espera obtener insights valiosos que contribuyan a una mejor comprensión del mercado de autopartes en México y su rol crítico dentro de la industria automotriz. Estos hallazgos podrían ofrecer directrices para la toma de decisiones estratégicas por parte de los actores de la industria, así como para el diseño de políticas públicas que promuevan el crecimiento y la sostenibilidad del sector. La metodología y los resultados de este análisis estarán fundamentados en la información detallada proporcionada en las bases de datos, cuyas fuentes se encuentran meticulosamente documentadas en el README adjunto a las bases de datos, asegurando así la transparencia y la fiabilidad de la investigación realizada.

Importaciónes, Exportaciónes y Producción de Autopartes

mx_autoparts_market <- read_csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_autos_mx/mx_autoparts_market.csv")

# Colores
colors <- c("Producción local total" = "#00BFC4",
            "Exportaciones totales" = "#F8766D",
            "Importaciones totales" = "#7CAE00",
            "Importaciones de EE.UU." = "#C77CFF")


# Usar ggplot2 para graficar directamente los datos
ggplot(data = mx_autoparts_market) +
  geom_line(aes(x = year, y = total_local_production, group = 1, colour = "Producción local total"), size = 1) +
  geom_line(aes(x = year, y = total_exports, group = 1, colour = "Exportaciones totales"), size = 1) +
  geom_line(aes(x = year, y = total_imports, group = 1, colour = "Importaciones totales"), size = 1) +
  geom_line(aes(x = year, y = imports_from_US, group = 1, colour = "Importaciones de EE.UU."), size = 1) +
  geom_point(aes(x = year, y = total_local_production, colour = "Producción local total"), size = 3) +
  geom_point(aes(x = year, y = total_exports, colour = "Exportaciones totales"), size = 3) +
  geom_point(aes(x = year, y = total_imports, colour = "Importaciones totales"), size = 3) +
  geom_point(aes(x = year, y = imports_from_US, colour = "Importaciones de EE.UU."), size = 3) +
  scale_colour_manual(values = colors) +
  labs(title = "Mercado de Autopartes en México (2018-2022)",
       x = "Año",
       y = "Valor (en miles de millones de USD)",
       colour = "Variable") +
  theme_minimal() 

1. Producción Local Total: - La línea que representa la producción local total muestra una tendencia decreciente de 2018 a 2019. - Hay una leve recuperación en 2020, seguida de una caída en 2021, y un ligero aumento en 2022. - Esta tendencia puede indicar desafíos en el sector de la producción o cambios en la demanda interna.

2. Exportaciones Totales: - Las exportaciones muestran una reducción significativa en 2020, posiblemente debido al impacto de la pandemia de COVID-19 en el comercio global. - Se observa una recuperación fuerte en 2021 y 2022, indicando una posible resiliencia o adaptación del mercado de exportación.

3. Importaciones Totales: - Las importaciones presentan un incremento constante a lo largo de los años, con una pequeña disminución en 2021. - La tendencia ascendente podría reflejar una creciente dependencia de componentes externos o un aumento en la demanda de autopartes no producidas localmente.

4. Importaciones de EE.UU.: - Las importaciones desde EE.UU. han disminuido significativamente desde 2018 hasta 2020. - Hay un aumento notable en 2021, que se revierte en 2022, sugiriendo fluctuaciones en las dinámicas comerciales con EE.UU.

Mercado de Autopartes Mx

mx_autoparts_market <- na.omit(mx_autoparts_market)

turquoise_palette <- c("#8ae0db", "#5dc1b9", "#42a8a1", "#239089")

# Crear la gráfica de barras con escala de color personalizada
ggplot(mx_autoparts_market, aes(x = factor(year), y = total_market_size, fill = total_market_size)) +
  geom_bar(stat = "identity") +
  scale_fill_gradientn(colors = turquoise_palette) +
  labs(x = "Año", y = "Tamaño Total del Mercado (en miles de millones de USD)",
       title = "Tamaño Total del Mercado de Autopartes en México (2018-2022)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

1. Impacto de la Pandemia en 2020: - La marcada caída en 2020 puede correlacionarse con la pandemia de COVID-19, que afectó globalmente la producción y venta de automóviles. Para una empresa como FORM, especializada en empaques para autopartes, esto podría haber representado un reto significativo, posiblemente llevando a una reducción en la demanda de sus productos de empaquetado.

2. Recuperación Post-Pandemia: - El rebote en 2021 sugiere una recuperación post-pandemia que habría podido generar un aumento en la demanda de vehículos y, consecuentemente, de autopartes. Esto puede haber sido una oportunidad para FORM de expandir o diversificar su línea de productos de empaque, aprovechando la reactivación del mercado.

3. Innovación como Factor de Crecimiento: - La innovación de productos de empaque que permiten ahorros significativos en espacio y costos de logística por parte de FORM podría haber sido un factor determinante en su potencial de crecimiento durante el periodo de recuperación económica, especialmente considerando la tendencia creciente hacia la eficiencia y sostenibilidad en la industria automotriz.

4. Potencial para el Futuro: - Dada la tendencia de recuperación del mercado en 2022, empresas como FORM están bien posicionadas para capitalizar el crecimiento continuo de la industria automotriz. La adaptación a las nuevas normativas ambientales y la mejora en la eficiencia de la cadena de suministro serán claves para su éxito futuro.

Industria del cartón

carton_exp = read.csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_carton/temporary/Exporters of Carton boxes cases of corrugated paper or board 2020-2021.csv")
carton_imp = read.csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_carton/temporary/Importers of Cartons boxes cases of corrugated paper or board 2020-2021.csv")
electric_2016=read.csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_autos_usa/temporary/mx_venta_vehiculos_hibridos_electricos_2016.csv")
electric_2017=read.csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_autos_usa/temporary/mx_venta_vehiculos_hibridos_electricos_2017.csv")
electric_2018=read.csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_autos_usa/temporary/mx_venta_vehiculos_hibridos_electricos_2018.csv")
electric_2019=read.csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_autos_usa/temporary/mx_venta_vehiculos_hibridos_electricos_2019.csv")
electric_2020=read.csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_autos_usa/temporary/mx_venta_vehiculos_hibiridos_electricos_2020.csv")
electric_2021=read.csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_autos_usa/temporary/mx_venta_vehiculos_hibridos_electricos_2021.csv")
electric_2022=read.csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_autos_usa/temporary/mx_venta_vehiculos_hibridos_electricos_2022.csv")
electric_2023=read.csv("/Users/daviddrums180/Tec/Case_Study_Form/databases/industry_autos_usa/temporary/mx_venta_vehiculos_hibridos_electricos_2023.csv")

Exportaciones

# Filtrar los 15 países con mayores valores de comercio de exportación
top_countries <- carton_exp %>%
  group_by(Country) %>%
  summarize(TotalTradeValue = sum(Trade.Value)) %>%
  top_n(15, TotalTradeValue) %>%
  arrange(desc(TotalTradeValue))

# Unir los datos filtrados con el data.frame original para obtener los datos completos de esos países
top_countries_data <- carton_exp %>%
  filter(Country %in% top_countries$Country)

# Crear el gráfico
ggplot(top_countries_data, aes(x = reorder(Country, Trade.Value), y = Trade.Value)) +
  geom_col(fill = "steelblue") +
  coord_flip() + # Hacer que el gráfico sea horizontal para mejor lectura
  labs(title = "Top 15 Países en Valor de Exportación de Cartón",
       x = "País",
       y = "Valor de Comercio (USD)") +
  theme_minimal() +
  theme(plot.title = element_text(size = 14, face = "bold"),
        axis.title.x = element_text(size = 12),
        axis.title.y = element_text(size = 12),
        axis.text.x = element_text(size = 10),
        axis.text.y = element_text(size = 10))

El análisis de las exportaciones globales de cartón revela que México se posiciona como uno de los líderes en este sector, destacándose por sus significativos valores de exportación. Esta fortaleza en el mercado del cartón refleja no solo la alta competitividad de la industria mexicana, sino también su capacidad para producir materiales de calidad superior. Para una empresa emergente especializada en cartón para autopartes, esto representa una oportunidad única para aprovechar la infraestructura existente, las economías de escala y las redes de suministro eficientes dentro de México.

ggplot(carton_exp, aes(x = Continent, y = Trade.Value.Growth * 100, fill = Continent)) +
  geom_boxplot() +
  scale_y_continuous(limits = c(0, 50), breaks = seq(0, 50, 10), labels = paste0(seq(0, 50, 10), "%")) +
  labs(title = "Crecimiento del Valor de Comercio de Exportaciones de Cartón por Continente",
       x = "Continente",
       y = "Crecimiento del Valor de Comercio (%)") +
  theme_minimal()

En cuanto al crecimiento de la industria del cartón por continente, podemos ver que Oceanía es el continente con el mayor porcentaje de crecimiento, sin embargo, la mediana del continente norteamericano es de poco menos del 20%, lo que indica que hay una tendencia positiva de esta industria en nuestro continente.

Importaciones

# Filtrar los 15 países con mayores valores de comercio de importación

top_countries_2 <- carton_imp %>%
  group_by(Country) %>%
  summarize(TotalTradeValue = sum(Trade.Value)) %>%
  top_n(15, TotalTradeValue) %>%
  arrange(desc(TotalTradeValue))

# Unir los datos filtrados con el data.frame original para obtener los datos completos de esos países
top_countries_data_2 <- carton_imp %>%
  filter(Country %in% top_countries_2$Country)

# Crear el gráfico
ggplot(top_countries_data_2, aes(x = reorder(Country, Trade.Value), y = Trade.Value)) +
  geom_col(fill = "blue") +
  coord_flip() + 
  labs(title = "Top 15 Países en Valor de Importación de Cartón",
       x = "País",
       y = "Valor de Comercio (USD)") +
  theme_minimal() +
  theme(plot.title = element_text(size = 14, face = "bold"),
        axis.title.x = element_text(size = 12),
        axis.title.y = element_text(size = 12),
        axis.text.x = element_text(size = 10),
        axis.text.y = element_text(size = 10))

En cuanto a las importaciones, México se consolida como el cuarto mayor importador mundial de cartón, destacando su rol clave en la industria global. Justo delante, Estados Unidos ocupa la segunda posición, reflejando la intensa actividad comercial y la demanda de materiales de calidad entre estos países vecinos. Esta situación subraya la importancia estratégica de México en el mercado de cartón y su cercanía con uno de los mayores importadores, Estados Unidos, potenciando las oportunidades de sinergia y cooperación transfronteriza en la cadena de suministro.

Industria de vehículos eléctricos

# Crear una lista de dataframes para iterar 
electric_dfs <- list(electric_2016 = electric_2016, electric_2017 = electric_2017,
                     electric_2018 = electric_2018, electric_2019 = electric_2019,
                     electric_2020 = electric_2020, electric_2021 = electric_2021,
                     electric_2022 = electric_2022, electric_2023 = electric_2023)

# Inicializar un vector para almacenar los totales de ventas de vehículos eléctricos por año
total_sales_by_year <- numeric(length(electric_dfs))
names(total_sales_by_year) <- names(electric_dfs)

# Sumar las ventas de vehículos eléctricos por año
for (year in names(electric_dfs)) {
  total_sales_by_year[year] <- sum(electric_dfs[[year]]$VEH_ELECTR, na.rm = TRUE)
}

# Convertir a data.frame
sales_df <- data.frame(Year = names(total_sales_by_year), 
                       ElectricVehicleSales = total_sales_by_year)

# Ver el resultado
print(sales_df)
##                        Year ElectricVehicleSales
## electric_2016 electric_2016                  254
## electric_2017 electric_2017                  237
## electric_2018 electric_2018                  201
## electric_2019 electric_2019                  305
## electric_2020 electric_2020                  449
## electric_2021 electric_2021                 1140
## electric_2022 electric_2022                 5631
## electric_2023 electric_2023                 4130
# Asumiendo que sales_df ya está creado y contiene las columnas 'Year' y 'ElectricVehicleSales'
ggplot(sales_df, aes(x = Year, y = ElectricVehicleSales)) +
  geom_col(fill = "steelblue", color = "black") + # Usamos barras con colores personalizados
  geom_text(aes(label = ElectricVehicleSales), vjust = -0.5, size = 3.5) + # Añadir etiquetas de texto sobre las barras
  labs(title = "Ventas de Vehículos Eléctricos en México por Año",
       subtitle = "Datos de ventas desde 2016 hasta 2023",
       x = "Año",
       y = "Ventas de Vehículos Eléctricos") +
  theme_minimal() + # Tema minimalista
  theme(plot.title = element_text(hjust = 0.5, size = 16, face = "bold"), # Centrar y dar formato al título
        plot.subtitle = element_text(hjust = 0.5, size = 12), # Centrar el subtítulo
        axis.title.x = element_text(size = 14, face = "bold"), # Formato para el título del eje X
        axis.title.y = element_text(size = 14, face = "bold"), # Formato para el título del eje Y
        axis.text.x = element_text(angle = 45, hjust = 1)) # Rotar las etiquetas del eje X para mejorar la legibilidad

Como se puede apreciar en la gráfica, las ventas en México de los vehículos eléctricos tienen una clara tendencia positiva desde hace varios años, esto refleja la oportunidad y la necesidad de que empresas como FORM adapten su oferta de soluciones a las nuevas autopartes que requieren este nuevo tipo de vehículos.

#Se detectó un error en ID_ENTIDAD, existiendo el ID=99. 
# Filtrar para eliminar ID_ENTIDAD = 99
datos_filtrados <- electric_2023 %>%
  filter(ID_ENTIDAD != 99)



# Agrupar datos por ID_ENTIDAD y sumar las ventas de vehículos eléctricos
ventas_por_estado <- datos_filtrados %>%
  group_by(ID_ENTIDAD) %>%
  summarise(Total_VEH_ELECTR = sum(VEH_ELECTR, na.rm = TRUE))

estados_mexico <- c("Aguascalientes", "Baja California", "Baja California Sur", "Campeche", "Chiapas",
                    "Chihuahua", "Ciudad de México", "Coahuila", "Colima", "Durango", "Guanajuato",
                    "Guerrero", "Hidalgo", "Jalisco", "México", "Michoacán", "Morelos", "Nayarit",
                    "Nuevo León", "Oaxaca", "Puebla", "Querétaro", "Quintana Roo", "San Luis Potosí",
                    "Sinaloa", "Sonora", "Tabasco", "Tamaulipas", "Tlaxcala", "Veracruz", "Yucatán", "Zacatecas")

datos_filtrados$ID_ENTIDAD <- as.numeric(datos_filtrados$ID_ENTIDAD)

# Agregar una nueva columna con los nombres de los estados
datos_filtrados <- datos_filtrados %>%
  mutate(Estado = estados_mexico[ID_ENTIDAD])

# Crear la gráfica
ggplot(ventas_por_estado, aes(x = factor(ID_ENTIDAD), y = Total_VEH_ELECTR, fill = factor(ID_ENTIDAD))) +
  geom_bar(stat = "identity", color = "black", show.legend = FALSE) +
  scale_fill_viridis_d() +
  labs(title = "Ventas de Vehículos Eléctricos de México por Estado en 2023",
       x = "ID del Estado",
       y = "Total de Ventas de Vehículos Eléctricos",
       caption = "Nota: ID del Estado: 1 = Aguascalientes, etc. ID_ENTIDAD = 99 excluido.") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1))

En cuanto a los estados con mayores ventas de vehículos eléctricos en el último año, destacan los estados con las capitales más importantes del país como Nuevo León, CDMX, Jalisco, Querétaro y Puebla. Esto puede representar para FORM oportunidades en cuanto a cómo enfocar su cadena de suministro para las mayores ventas de sus clientes.

FODA Cruzado

Apartir de los antecedentes de la empresa y el contexto de la industrias de México y E.U.A. elaborar FODA cruzado que identifique y describa 2-3 estrategias a seguir por parte de la empresa en el corto plazo.

Fortalezas:

  1. Expertos en desarrollar soluciones de empaque sostenibles e innovadoras con un enfoque en la industria automotriz, optimizando el espacio de almacenamiento, así como los costos logísticos lo que indica un profundo entendimiento de las necesidades del sector automotriz.
  2. Asociaciones con marcas de alto prestigio, la empresa de Form ha establecido relaciones comerciales como lo es Tesla, lo que nos indica la alta calidad y confiabilidad de sus soluciones de empaque.
  3. Compromiso con la sostenibilidad, la empresa integra prácticas sostenibles en su modelo de negocio, desde reducciones de uso de materiales hasta la optimización de logística, que se alinean con la demanda actual de la industria hacia prácticas más ecológicas.

Oportunidades:

  1. Crecimiento del mercado en la industria con empaques sostenibles. La conciencia ambiental y regulaciones de la sostenibilidad, presentan una gran oportunidad para la empresa en liderar el desarrollo y oferta de soluciones en los empaques sostenibles.
  2. Demanda creciente de empaques personalizados para los clientes debido a cambios en los consumidores. La tendencia hacia servicios y productos personalizados para sus clientes, requiere una mayor demanda de empaques que se ajusten a las necesidades individuales de sus clientes.
  3. Oportunidad de expansión en industrias fuera de la industria automotriz que requieren de soluciones innovadoras de empaque. Otras industrias también requieren de soluciones de empaque innovadoras lo que presenta una oportunidad para la empresa de expandir su mercado a otros sectores.

Debilidades:

  1. Actualmente se encuentran en potencial dependencia de la industria automotriz. Esto podría representar un alto riesgo si el sector llegará a enfrentar disminuciones en la demanda o desafíos económicos.
  2. Necesidad en estar actualizados continuamente frente a tecnologías en desarrollo de empaque. Mantenerse en constante innovación requiere inversión en investigaciones y desarrollo, lo que puede ser un reto en recursos y capital.
  3. Limitaciones en la diversificación de productos. La especialización que tienen sobre los empaques de autopartes podría limitar la capacidad de la empresa para capitalizar y explorar oportunidades en otros mercados y productos.

Amenazas:

  1. Constante cambio en las regulaciones ambientales que pueden afectar los materiales para realizar los empaques. Puede haber un gran impacto al usar ciertos procesos y materiales que requieren de adaptaciones costosas.
  2. Gran competencia creciente en el sector de empaques sostenibles. El crecimiento de la industria y su demanda de soluciones de empaques sostenibles atrae a nuevos competidores, esto incrementa la presión para la empresa por diferenciarse y continuar innovando.
  3. Volatilidad en los costos de materiales debido a fluctuaciones del mercado. Esto puede afectar los márgenes de beneficio y la competitividad de precios de las soluciones de FORM.

Estrategias:

Estrategias FODA Cruzado para FORM

Fortalezas-Oportunidades (FO)
  • Sostenibilidad e Innovación: Utilizar la experiencia y el compromiso de la empresa con la sostenibilidad para poder liderar en la industria y en el mercado con empaques renovables y ecológicos para seguir creciendo ante la demanda.
  • Expansión en Servicios Personalizados: Desarrollar soluciones personalizadas a los clientes y mejorar su relación con marcas de prestigio.
Debilidades-Oportunidades (DO)
  • Mitigar dependencias en el mercado: Ampliar el mercado hacia nuevas industrias, para reducir la dependencia del sector automotriz, creciendo a nuevos mercados con demanda creciente a soluciones innovadoras.
  • Colaboraciones con Innovación: Realizar colaboraciones estratégicas para dividir el costo de riesgo de innovación y desarrollo, dándole a la empresa un gran alcance para ser el líder en la industria.
Fortalezas-Amenazas (FA)
  • Liderazgo ante Cambios regulatorios: Emplear compromiso con la innovación y sostenibilidad para que la empresa se adapte ante los cambios en regulaciones ecológicas, posicionando a FORM como un referente en cumplimiento y adaptabilidad.
  • Valor agregado frente a la Competencia: Fortalecer a la empresa a través de su confiabilidad con sus clientes, aprovechando su calidad para destacarse en el mercado competitivo, así mismo aprovechando sus colaboraciones con marcas de alto prestigio.
Debilidades-Amenazas (DA)
  • Cobertura de riesgo en Costos: Realizar estrategias para tomar medidas de prevención para protegerse contra la volatilidad de los precios de los materiales, como lo es la diversificación de los proveedores y los contratos de la empresa a largo plazo.
  • Programas de Lealtad con Clientes: Implementar programas de colaboración y lealtad con los clientes actuales, para poder mejorar la relación a largo plazo y mitigar el impacto de la competencia y las fluctuaciones del mercado.

PESTLE

Con base en el análisis de las industrias de México y E.U.A. identificar variables / factores relevantes para la elaboración de PESTLE y describir 2-3 estrategias a seguir por parte de la empresa en el corto plazo.

Políticos.

EE.UU. advierte terminar tratado de comercio con México por fábricas de carros chinos. Las futuras elecciones pueden ser un factor muy importante en la industria automotriz, ya que según BBC News, Trump se muestra de manera muy hostil ante los fabricantes de automóviles. Por lo que, puede que imponga alguna ley que afecte negativamente la industria. El Tratado entre México, Estados Unidos y Canadá (T-MEC) establece reglas para el comercio entre los tres países, incluyendo la industria automotriz. El T-MEC ha sido positivo para la industria automotriz mexicana, ya que ha aumentado la producción y las exportaciones. El gobierno mexicano ha implementado una serie de políticas para promover la industria automotriz, como la creación de un fondo de apoyo a la industria y la reducción de impuestos a la importación de autopartes.

Económicos.

Sector automotriz, con la mayor demanda de espacios industriales por Nearshoring. Industria automotriz aumenta 7.8% la producción en febrero. México recibirá 2 mil 300 mdd de inversión extranjera en autopartes en 2024: INA. El nearshoring puede reducir los costos de producción al aprovechar la mano de obra más barata en países cercanos. Esto puede mejorar la competitividad de FORM en el mercado. La tasa de interés en Estados Unidos ha aumentado en los últimos años. Esto ha encarecido el crédito para los consumidores, lo que podría afectar la demanda de vehículos.

Sociales.

La clase media en México está creciendo. Esto ha aumentado la demanda de vehículos, ya que las personas de la clase media tienen más dinero para gastar. Las preocupaciones ambientales están aumentando en Estados Unidos. Esto podría afectar la demanda de vehículos, ya que los consumidores podrían optar por comprar vehículos más eficientes en combustible o vehículos eléctricos.

Tecnológicos.

Se busca que en México solo se vendan autos eléctricos. Protagonistas de la industria automotriz en México han unido fuerzas para crear la Electro Movilidad Asociación (EMA), alianza que nace con el objetivo de alcanzar el 100 por ciento de ventas de vehículos eléctricos para el año 2035.

Legales.

Exportación de autos made in México crece 22.6% en febrero y acelera a máximo histórico. Stellantis anuncia importante plan de inversiones para América Latina. Las regulaciones de seguridad para los vehículos están aumentando en todo el mundo. Esto está obligando a las empresas automotrices a invertir en nuevas tecnologías de seguridad.

Ecológicos.

La Industria Nacional de Autopartes aseguró que la producción de baterías para autos eléctricos en Norteamérica es fundamental para cumplir con las reglas de origen del T-MEC. El cambio climático es una preocupación importante para la industria automotriz. Las empresas automotrices están desarrollando vehículos más eficientes en combustible y vehículos eléctricos para reducir su impacto ambiental.

Definición de Problemáticas

Situación Problema 1: Rotación de Personal

Explorar, definir, y describir cuáles son los principales factores del clima organizacional de FORM que propician la satisfacción y/o no satisfacción de trabajar en dicha empresa.

La rotación de personal se ha identificado como el desafío más crítico que enfrenta FORM en el presente. A pesar de nuestros esfuerzos continuos para crear un ambiente laboral atractivo y retener a nuestros valiosos empleados, nos encontramos con una tasa de rotación especialmente alta entre los operadores. Este fenómeno no solo afecta la continuidad y la eficiencia de nuestras operaciones, sino que también incrementa los costos asociados con el reclutamiento y la capacitación de nuevo personal.

  • Principales Puntos:
    • La estabilidad familiar y las condiciones laborales son factores significativos que influyen en la decisión de los empleados de permanecer en la empresa.
    • Los jóvenes, especialmente aquellos sin compromisos familiares, tienden a buscar oportunidades de desarrollo profesional fuera de FORM.
    • Es crucial mejorar nuestras estrategias de reclutamiento y retención para abordar las causas subyacentes de la rotación de personal.

Situación Problema 2: Predicción de Demanda

Explorar, desarrollar, y describir la(s) posible(s) estrategia(s) de predicción de la demanada de productos fabricados por la empresa FORM.

La predicción precisa de la demanda representa un desafío igualmente significativo para FORM, dada la variabilidad inherente en la producción y venta de autopartes. La habilidad para anticipar con exactitud cuántas unidades de un determinado componente serán necesarias es crucial para optimizar nuestros procesos de producción y empaque, y para asegurar que se maximice la eficiencia en el uso de recursos.

  • Principales Puntos:
    • La naturaleza fluctuante de la demanda automotriz complica la planificación y gestión de inventarios.
    • Es esencial desarrollar herramientas y procesos más sofisticados para mejorar la precisión en nuestras predicciones de demanda.
    • La adaptabilidad y la capacidad de responder rápidamente a los cambios en el mercado son fundamentales para mantener nuestra competitividad.

Preguntas de Analisis

Elaborar 4-6 preguntas relacionadas con la situación problema seleccionada que se puedan responder mediante el análisis de datos.

Situación Problema 1: Rotación de Personal

  • ¿Qué está causando la rotación de personal tan alta?

  • ¿Existe algún momento del año donde se den más bajas dentro de la empresa?

  • ¿Cómo se siente la gente dentro de su trabajo actual?

  • ¿Qué factor ayuda a que el personal dure más tiempo dentro de la empresa?

  • ¿En qué parte de la empresa el trabajador se siente más inconforme y cuál es su perfil?

Analisis de Exploración de Datos

Transformaciones Necesarias

FORM Bajas

# Limpieza de Fecha
form_bajas$`Fecha de Nacimiento` <- as.Date(form_bajas$`Fecha de Nacimiento` - ifelse(form_bajas$`Fecha de Nacimiento` > 60, 1, 0), origin="1899-12-30")
form_bajas$`Fecha de Alta` <- as.Date(form_bajas$`Fecha de Alta` - ifelse(form_bajas$`Fecha de Alta` > 60, 1, 0), origin="1899-12-30")
form_bajas$`Primer Mes` <- as.Date(form_bajas$`Primer Mes` - ifelse(form_bajas$`Primer Mes` > 60, 1, 0), origin="1899-12-30")
form_bajas$`Cuarto Mes` <- as.Date(form_bajas$`Cuarto Mes` - ifelse(form_bajas$`Cuarto Mes` > 60, 1, 0), origin="1899-12-30")
form_bajas$`Fecha de Baja` <- as.Date(form_bajas$`Fecha de Baja` - ifelse(form_bajas$`Fecha de Baja` > 60, 1, 0), origin="1899-12-30")

# Calcular la antigüedad como la diferencia entre Fecha de Baja y Fecha de Alta
form_bajas$Antiguedad <- abs(as.numeric(form_bajas$`Fecha de Baja` - form_bajas$`Fecha de Alta`, units = "days"))

head(form_bajas)
## # A tibble: 6 × 27
##     No. Apellidos      Nombre `Fecha de Nacimiento` Género RFC   `Fecha de Alta`
##   <dbl> <chr>          <chr>  <date>                <chr>  <chr> <date>         
## 1     1 Perez Chavarr… Yessi… 1985-02-12            Femen… PECY… 2022-09-04     
## 2     1 Pecina Aleman  Blanc… 1966-05-24            Femen… PEAB… 2022-10-05     
## 3     1 Suarez Romo    Julio… 1969-06-26            Mascu… SURJ… 2017-11-30     
## 4     1 Ortiz De La T… Fermi… 1966-07-06            Femen… OITF… 2022-05-31     
## 5     1 Gallegos Manz… Veron… 1973-11-27            Femen… GAMV… 2022-10-21     
## 6     1 Guzman Reyes   Carlo… 2002-11-24            Mascu… GURC… 2023-01-05     
## # ℹ 20 more variables: `Primer Mes` <date>, `Cuarto Mes` <date>,
## #   `Fecha de Baja` <date>, `Motivo de Baja` <chr>, Puesto <chr>, Dpto <chr>,
## #   Imss <chr>, SD <chr>, `Factor de Crédito Infonavit` <chr>,
## #   `No. De Crédito Infonavit` <chr>, CURP <chr>, Calle <chr>, Número <chr>,
## #   Colonia <chr>, Municipio <chr>, Estado <chr>, CP <dbl>,
## #   `Estado Civil` <chr>, `Número de Télefono` <dbl>, Antiguedad <dbl>

FORM RH

# Asegurándonos de que las fechas estén en formato adecuado
form_rh$`Fecha de nacimiento` <- as.Date(form_rh$`Fecha de nacimiento`, origin = "1899-12-30")
form_rh$`Fecha de Alta` <- as.Date(form_rh$`Fecha de Alta`)
form_rh$`Fecha de Baja` <- as.Date(form_rh$`Fecha de Baja`)

# Calcular la Edad y la Duración en el trabajo
form_rh <- form_rh %>%
  mutate(
    Edad = interval(start = `Fecha de nacimiento`, end = Sys.Date()) %/% years(1),
    Duracion = case_when(
      is.na(`Fecha de Baja`) ~ interval(start = `Fecha de Alta`, end = Sys.Date()) %/% days(1),
      TRUE ~ interval(start = `Fecha de Alta`, end = `Fecha de Baja`) %/% days(1)
    )
  )

# Verificar los resultados
head(form_rh)
## # A tibble: 6 × 34
##     No. Apellido       Nombre `Fecha de nacimiento` Género RFC   `Fecha de Alta`
##   <dbl> <chr>          <chr>  <date>                <chr>  <chr> <date>         
## 1    17 ramirez ramir… sandr… 1990-02-11            femen… rars… 2022-08-22     
## 2    30 de luna ramos  lluvia 2002-06-12            femen… lurl… 2023-10-23     
## 3    31 contreras lop… melin… 1985-10-12            femen… colm… 2023-12-01     
## 4    32 romero ramirez nayda… 1993-10-29            femen… rorn… 2023-12-04     
## 5    28 granados sauc… sonia… 1984-06-22            femen… gass… 2023-08-21     
## 6    28 sauri viveros  said   2001-12-05            mascu… savs… 2023-08-16     
## # ℹ 27 more variables: `Primer Mes` <date>, `Cuarto Mes` <date>,
## #   `Fecha de Baja` <date>, Puesto <chr>, Dpto <chr>, Imss <chr>, SD <dbl>,
## #   `Factor de Crédito Infonavit` <chr>, `No. De Crédito Infonavit` <chr>,
## #   `Lugar de Nacimiento` <chr>, CURP <chr>, Calle <chr>, Número <chr>,
## #   Colonia <chr>, Municipio <chr>, Estado <chr>, CP <chr>,
## #   `Estado Civil` <chr>, `Número de Télefono` <chr>, Banco <chr>,
## #   `Correo Electronico` <chr>, `Causa de Baja` <chr>, …

FORM Bajas Espacial

form_bajas$CP <- as.character(form_bajas$CP)
cp_nl$d_codigo <- as.character(cp_nl$d_codigo)

stats_por_cp <- form_bajas %>%
  group_by(CP) %>%
  summarize(
    Conteo_Empleados = n(),
    Mediana_Antiguedad = median(Antiguedad, na.rm = TRUE),
    .groups = 'drop'
  )

form_bajas_espacial <- cp_nl %>%
  left_join(stats_por_cp, by = c("d_codigo" = "CP"))

# Reemplazar NA con 0 en las columnas de interés
form_bajas_espacial$Conteo_Empleados[is.na(form_bajas_espacial$Conteo_Empleados)] <- 0
form_bajas_espacial$Mediana_Antiguedad[is.na(form_bajas_espacial$Mediana_Antiguedad)] <- 0

head(form_bajas_espacial)
## Simple feature collection with 6 features and 3 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 2661927 ymin: 1481451 xmax: 2725620 ymax: 1529424
## Projected CRS: Lambert_Conformal_Conic
##   d_codigo Conteo_Empleados Mediana_Antiguedad                       geometry
## 1    66063                0                  0 MULTIPOLYGON (((2662011 152...
## 2    67495                0                  0 MULTIPOLYGON (((2716586 149...
## 3    67467                0                  0 MULTIPOLYGON (((2707035 148...
## 4    67494                0                  0 MULTIPOLYGON (((2718640 149...
## 5    67475                0                  0 MULTIPOLYGON (((2707164 151...
## 6    64010                0                  0 MULTIPOLYGON (((2670043 151...

FORM Satisfacción

# Lista de columnas específicas a transformar
columnas_a_transformar <- c("salario_bueno", "prestaciones_bueno", "jornada_no_excesiva", 
                            "ofrecimiento_herramientas", "no_molestia_temperatura", "estres_bajo", 
                            "facilidad_transporte", "zona_trabajo_comoda", "permanencia_form_futuro")

# Ajustar la función para manejar el typo y valores inesperados
codificar_respuestas <- function(respuesta) {
  # Corregir posibles typos
  respuesta <- gsub("Totalmende en desacuerdo", "Totalmente en desacuerdo", respuesta)
  
  # Usar switch para asignar valores numéricos
  switch(respuesta,
         "Totalmente en desacuerdo" = 1,
         "Medianamente en desacuerdo" = 2,
         "Ni de acuerdo ni en desacuerdo" = 3,
         "Medianamente de acuerdo" = 4,
         "Totalmente de acuerdo" = 5,
         NA) # Devolver NA para cualquier respuesta no reconocida
}

# Aplicar la codificación solo a las columnas seleccionadas, asegurando que todas las transformaciones son numéricas
form_satisfaccion[columnas_a_transformar] <- lapply(form_satisfaccion[columnas_a_transformar], function(x) as.numeric(sapply(x, codificar_respuestas)))

head(form_satisfaccion)
## # A tibble: 6 × 22
##   encuesta puesto      antiguedad razon_entrada salario_bueno prestaciones_bueno
##      <dbl> <chr>            <dbl> <chr>                 <dbl>              <dbl>
## 1        1 administra…          9 salario                   5                  4
## 2        2 costurera           36 otro                      4                  4
## 3        3 ayudante g…          4 ubicacion em…             2                  1
## 4        4 ayudante g…          2 ubicacion em…             5                  4
## 5        5 ayudante g…          1 ubicacion em…             3                  1
## 6        6 ayudante g…         36 razones pers…             4                  5
## # ℹ 16 more variables: jornada_no_excesiva <dbl>,
## #   ofrecimiento_herramientas <dbl>, no_molestia_temperatura <dbl>,
## #   estres_bajo <dbl>, facilidad_transporte <dbl>, zona_trabajo_comoda <dbl>,
## #   permanencia_form_futuro <dbl>, sufrido_situaciones_conflicto <chr>,
## #   molestias_puesto <chr>, sentimiento_form <chr>, edad <chr>, genero <chr>,
## #   estado_civil <chr>, municipio <chr>, nivel_escolar <chr>,
## #   personas_dependientes <dbl>

Exportación de Vehículos México

exp_vehiculos$Fecha <- as.yearqtr(exp_vehiculos$quarter, format = "%Y-Q%q")

Venta de Vehículos México

ventas_vehiculos$Fecha <- as.yearqtr(paste(ventas_vehiculos$ANIO, ventas_vehiculos$ID_MES, "1"), format = "%Y %m %d")

Preguntas de Análisis

Situación Problema 1: Rotación de Personal

¿Qué está causando la rotación de personal tan alta?

# Reunir todas las columnas de interés en dos columnas: 'pregunta' y 'respuesta'
datos_largos <- form_satisfaccion %>%
  pivot_longer(cols = c(salario_bueno, prestaciones_bueno, jornada_no_excesiva,
                        ofrecimiento_herramientas, no_molestia_temperatura,
                        estres_bajo, facilidad_transporte, zona_trabajo_comoda,
                        permanencia_form_futuro),
               names_to = "pregunta", values_to = "respuesta") %>%
  group_by(pregunta, respuesta) %>%
  summarise(n = n(), .groups = 'drop') %>%
  mutate(Percentage = n / sum(n))

# Ordenar las preguntas por el porcentaje de 'Muy en contra' que corresponde a la respuesta '1'
orden_preguntas <- datos_largos %>%
  filter(respuesta == 1) %>%
  arrange((Percentage)) %>%
  pull(pregunta)

# Convertir 'respuesta' a un factor con etiquetas para la leyenda
datos_largos$respuesta <- factor(datos_largos$respuesta, levels = 1:5,
                                 labels = c("Muy en contra", "En contra", 
                                            "Neutral", "A favor", 
                                            "Muy a favor"))

# Paleta de colores personalizada para los niveles de acuerdo
colores_personalizados <- c("#d7191c", "#fdae61", "#c8c6c4", "#bbbcb8", "#8d8c86")

# Generar el gráfico
g <- ggplot(datos_largos, aes(x = factor(pregunta, levels = orden_preguntas), y = Percentage, fill = respuesta)) +
  geom_bar(stat = "identity", position = "fill") +
  scale_fill_manual(values = colores_personalizados, labels = levels(datos_largos$respuesta)) +
  coord_flip() +
  labs(y = "Porcentaje", x = "", fill = "") +
  scale_y_continuous(labels = percent_format()) +
  theme_minimal() +
  theme(legend.position = "bottom",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.title = element_blank(),
        legend.key.size = unit(0.5, 'lines'))

# Para guardar el gráfico en un archivo
g

summary(form_satisfaccion)
##     encuesta         puesto            antiguedad    razon_entrada     
##  Min.   :  1.00   Length:106         Min.   : 1.00   Length:106        
##  1st Qu.: 27.25   Class :character   1st Qu.: 1.00   Class :character  
##  Median : 53.50   Mode  :character   Median : 9.00   Mode  :character  
##  Mean   : 53.50                      Mean   :14.08                     
##  3rd Qu.: 79.75                      3rd Qu.:34.50                     
##  Max.   :106.00                      Max.   :36.00                     
##  salario_bueno   prestaciones_bueno jornada_no_excesiva
##  Min.   :1.000   Min.   :1.000      Min.   :1.00       
##  1st Qu.:3.000   1st Qu.:2.000      1st Qu.:4.00       
##  Median :4.000   Median :4.000      Median :5.00       
##  Mean   :3.792   Mean   :3.274      Mean   :4.16       
##  3rd Qu.:5.000   3rd Qu.:5.000      3rd Qu.:5.00       
##  Max.   :5.000   Max.   :5.000      Max.   :5.00       
##  ofrecimiento_herramientas no_molestia_temperatura  estres_bajo   
##  Min.   :1.000             Min.   :1.000           Min.   :1.000  
##  1st Qu.:3.000             1st Qu.:1.000           1st Qu.:3.000  
##  Median :5.000             Median :3.000           Median :4.000  
##  Mean   :3.877             Mean   :3.123           Mean   :3.679  
##  3rd Qu.:5.000             3rd Qu.:5.000           3rd Qu.:5.000  
##  Max.   :5.000             Max.   :5.000           Max.   :5.000  
##  facilidad_transporte zona_trabajo_comoda permanencia_form_futuro
##  Min.   :1.000        Min.   :1.000       Min.   :1.000          
##  1st Qu.:4.000        1st Qu.:4.000       1st Qu.:3.000          
##  Median :5.000        Median :5.000       Median :5.000          
##  Mean   :4.009        Mean   :4.311       Mean   :4.038          
##  3rd Qu.:5.000        3rd Qu.:5.000       3rd Qu.:5.000          
##  Max.   :5.000        Max.   :5.000       Max.   :5.000          
##  sufrido_situaciones_conflicto molestias_puesto   sentimiento_form  
##  Length:106                    Length:106         Length:106        
##  Class :character              Class :character   Class :character  
##  Mode  :character              Mode  :character   Mode  :character  
##                                                                     
##                                                                     
##                                                                     
##      edad              genero          estado_civil        municipio        
##  Length:106         Length:106         Length:106         Length:106        
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##  nivel_escolar      personas_dependientes
##  Length:106         Min.   :0.000        
##  Class :character   1st Qu.:0.000        
##  Mode  :character   Median :1.000        
##                     Mean   :1.085        
##                     3rd Qu.:2.000        
##                     Max.   :3.000
variables_categoricas <- c("salario_bueno", "prestaciones_bueno", "jornada_no_excesiva", 
                           "ofrecimiento_herramientas", "no_molestia_temperatura", "estres_bajo", 
                           "facilidad_transporte", "zona_trabajo_comoda", "permanencia_form_futuro")

# Calculamos los porcentajes por categoría para cada variable
porcentajes_categorias <- form_satisfaccion %>%
  select(all_of(variables_categoricas)) %>%
  pivot_longer(cols = everything(), names_to = "Variable", values_to = "Valor") %>%
  group_by(Variable) %>%
  count(Valor) %>%
  mutate(Porcentaje = n / sum(n) * 100) %>%
  ungroup() %>%
  select(-n)  # Si no necesitas la columna de conteos, puedes omitirla.

# Convertir a un formato ancho específico para cada variable y valor
porcentajes_ancho <- porcentajes_categorias %>%
  pivot_wider(names_from = Valor, values_from = Porcentaje, names_prefix = "Categoria_") %>%
  select(Variable, starts_with("Categoria_")) %>%
  arrange(Variable)

# Modificamos 'porcentajes_ancho' para formatear los porcentajes
porcentajes_ancho <- porcentajes_ancho %>%
  mutate(across(starts_with("Categoria_"), ~sprintf("%.1f%%", .)))

# Ver los resultados
print(porcentajes_ancho)
## # A tibble: 9 × 6
##   Variable           Categoria_1 Categoria_2 Categoria_3 Categoria_4 Categoria_5
##   <chr>              <chr>       <chr>       <chr>       <chr>       <chr>      
## 1 estres_bajo        12.3%       8.5%        18.9%       19.8%       40.6%      
## 2 facilidad_transpo… 14.2%       8.5%        1.9%        13.2%       62.3%      
## 3 jornada_no_excesi… 7.5%        5.7%        9.4%        17.9%       59.4%      
## 4 no_molestia_tempe… 33.0%       6.6%        11.3%       13.2%       35.8%      
## 5 ofrecimiento_herr… 18.9%       1.9%        8.5%        14.2%       56.6%      
## 6 permanencia_form_… 8.5%        4.7%        14.2%       19.8%       52.8%      
## 7 prestaciones_bueno 19.8%       17.9%       9.4%        20.8%       32.1%      
## 8 salario_bueno      10.4%       10.4%       7.5%        33.0%       38.7%      
## 9 zona_trabajo_como… 7.5%        4.7%        3.8%        17.0%       67.0%

¿Existe algún momento del año donde se den más bajas dentro de la empresa?

# Agregar una columna que indique el mes de la fecha de baja
form_bajas$Mes <- month(form_bajas$`Fecha de Baja`)
form_bajas$Año <- year(form_bajas$`Fecha de Baja`)

# Agrupar por mes y género, luego contar las bajas
bajas_por_mes_genero <- form_bajas %>%
  group_by(Mes, Género) %>%
  summarise(Conteo = n(), .groups = 'drop') %>%
  arrange(Mes)

# Graficar las bajas por mes para cada género
ggplot(bajas_por_mes_genero, aes(x = Mes, y = Conteo, group = Género, color = Género)) +
  geom_line() +
  scale_x_continuous(breaks = 1:12, labels = month.name) +
  theme_minimal() +
  labs(title = "Bajas por Mes Dividido por Género",
       x = "Mes",
       y = "Número de Bajas",
       color = "Género")

# Configurar tmap para que intente reparar automáticamente los polígonos inválidos
tmap_options(check.and.fix = TRUE)

# Calcular los breaks para Conteo de Empleados excluyendo los ceros
conteo_empleados_values <- form_bajas_espacial$Conteo_Empleados[form_bajas_espacial$Conteo_Empleados > 0]
breaks_conteo <- c(-Inf, quantile(conteo_empleados_values, probs = seq(0, 1, by = 0.25), na.rm = TRUE))

# Calcular los breaks para Mediana de Antigüedad excluyendo los ceros
antiguedad_values <- form_bajas_espacial$Mediana_Antiguedad[form_bajas_espacial$Mediana_Antiguedad > 0]
breaks_antiguedad <- c(-Inf, quantile(antiguedad_values, probs = seq(0, 1, by = 0.25), na.rm = TRUE))

# Mapa para Conteo de Empleados
conteo_empleados_map <- tm_shape(form_bajas_espacial) + 
  tm_fill("Conteo_Empleados", palette = "Blues", style = "fixed", breaks = breaks_conteo, 
          title = "Conteo de Empleados", na.color = "white") +
  tm_borders() +
  tm_layout(frame = FALSE, legend.position = c("left", "bottom"))

# Mapa para Mediana de Antigüedad
mediana_antiguedad_map <- tm_shape(form_bajas_espacial) + 
  tm_fill("Mediana_Antiguedad", palette = "BuPu", style = "fixed", breaks = breaks_antiguedad, 
          title = "Mediana de Antigüedad", na.color = "white") +
  tm_borders() +
  tm_layout(frame = FALSE, legend.position = c("right", "bottom"))

# Configurar opciones de tmap para la visualización de los mapas
tmap_mode("view")

# Mostrar mapas lado a lado
tmap_arrange(conteo_empleados_map, mediana_antiguedad_map, nrow = 1)

¿Cómo se siente la gente dentro de su trabajo actual?

# Función ajustada para preprocesar texto
preparar_texto <- function(datos, columna) {
  datos %>%
    select(!!sym(columna)) %>%
    mutate(across(everything(), as.character)) %>%
    mutate(across(everything(), ~ gsub("\\d+", "", .))) %>%
    unnest_tokens(word, !!sym(columna))
}

# Función ajustada para análisis de sentimiento y wordcloud con colores personalizados
analizar_y_wordcloud <- function(datos, columna) {
  texto_preparado <- preparar_texto(datos, columna)
  
  # Obtener sentimiento
  emociones_df <- texto_preparado %>%
    inner_join(get_sentiments("nrc"), by = "word") %>%
    count(sentiment, sort = TRUE) %>%
    print()
  
  # Filtrar palabras para el wordcloud (aparición mínima: 3 veces)
  palabras_frecuentes <- texto_preparado %>%
    count(word, sort = TRUE) %>%
    filter(n >= 3)
  
  # Definir paleta de colores de gris claro a naranja
  colores_gris_naranja <- colorRampPalette(c("darkgrey", "orange"))(100)
  
  # Generar wordcloud con la paleta personalizada
  set.seed(123)
  wordcloud(words = palabras_frecuentes$word, freq = palabras_frecuentes$n, min.freq = 2,
            max.words = 100, random.order = FALSE, rot.per = 0.35, 
            colors = colores_gris_naranja)
}

analizar_y_wordcloud(form_satisfaccion, "molestias_puesto")
## # A tibble: 2 × 2
##   sentiment     n
##   <chr>     <int>
## 1 trust         3
## 2 negative      2

¿Qué factor ayuda a que el personal dure más tiempo dentro de la empresa?

ggplot(form_rh, aes(x = Estatus, y = Edad, fill = Estatus)) + 
  geom_boxplot(color = "black") +
  geom_jitter(position = position_jitterdodge(jitter.width = 0.2, dodge.width = 0.75), size = 2, alpha = 0.6) +
  labs(title = "Edad por Estatus",
       x = "Estatus",
       y = "Edad") +
  theme_minimal() +
  scale_fill_brewer(palette = "Pastel1") + 
  theme(plot.title = element_text(hjust = 0.5), 
        legend.position = "none", 
        axis.text = element_text(size = 12), 
        axis.title = element_text(size = 14), 
        panel.grid.major = element_line(colour = "grey", linetype = "dotted"), 
        panel.grid.minor = element_blank(), 
        panel.background = element_rect(fill = "white"))

conteos_genero <- form_rh %>%
  group_by(Género, Estatus) %>%
  summarise(Count = n(), .groups = 'drop')

# Ahora creamos el gráfico de barras apiladas con los colores especificados
ggplot(conteos_genero, aes(x = Género, y = Count, fill = Estatus)) + 
  geom_bar(stat = "identity", position = "fill") + 
  scale_fill_manual(values = c("activo" = "#00CDAC", "baja" = "darkgrey")) + 
  labs(title = "Proporción de Estatus por Género",
       x = "Género",
       y = "Proporción") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5),
        axis.text.x = element_text(hjust = 1))

conteos_estado_civil <- form_rh %>%
  group_by(`Estado Civil`, Estatus) %>%
  summarise(Count = n(), .groups = 'drop')

# Ahora creamos el gráfico de barras apiladas con los colores especificados
ggplot(conteos_estado_civil, aes(x = `Estado Civil`, y = Count, fill = Estatus)) + 
  geom_bar(stat = "identity", position = "stack") + # Conteos absolutos
  scale_fill_manual(values = c("activo" = "lightgreen", "baja" = "lightcoral")) + # Colores personalizados
  labs(title = "Total de Personas por Estado Civil y Estatus",
       x = "Estado Civil",
       y = "Total de Personas") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5),
        axis.text.x = element_text(angle = 45, hjust = 1))  

¿En qué parte de la empresa el trabajador se siente más inconforme y cuál es su perfil?

# Generar los datos para la variable 'permanencia_form_futuro'
datos_permanencia <- form_satisfaccion %>%
  group_by(permanencia_form_futuro) %>%
  summarise(Count = n()) %>%
  mutate(Percentage = Count / sum(Count) * 100)

# Paleta de colores personalizada: rojo, dorado, verde
colores_personalizados <- c("#d7191c", "#fdae61", "#ffffbf", "#a6d96a", "#1a9641")

# Gráfico de barras para 'permanencia_form_futuro'
ggplot(datos_permanencia, aes(x = factor(permanencia_form_futuro, levels = c(1, 2, 3, 4, 5)), y = Percentage, fill = as.factor(permanencia_form_futuro))) +
  geom_bar(stat = "identity") +
  scale_fill_manual(values = colores_personalizados) +
  scale_x_discrete(labels = c("Totalmente\nen desacuerdo", "Medianamente\nen desacuerdo", "Ni de acuerdo\nni en desacuerdo", "Medianamente\nde acuerdo", "Totalmente\nde acuerdo")) +
  xlab("Nivel de Acuerdo con la Permanencia a Futuro") +
  ylab("Porcentaje") +
  ggtitle("Distribución de Respuestas para 'Permanencia a Futuro'") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 0, hjust = 0.5, size = 8), 
        legend.title = element_blank(),
        legend.position = "bottom")

# Filtrar para obtener solo aquellos en desacuerdo con la permanencia a futuro (valor 1 o 2)
desacuerdo_permanencia <- form_satisfaccion %>% 
  filter(permanencia_form_futuro %in% c(1, 2))

# Selecciona solo las columnas de interés para el boxplot
columnas_interes <- c("salario_bueno", "prestaciones_bueno", "jornada_no_excesiva", 
                      "ofrecimiento_herramientas", "no_molestia_temperatura", "estres_bajo", 
                      "facilidad_transporte", "zona_trabajo_comoda")

# Convertir datos a formato largo para boxplots
datos_largos <- desacuerdo_permanencia %>%
  select(all_of(columnas_interes)) %>%
  pivot_longer(
    cols = everything(), 
    names_to = "Variable", 
    values_to = "Puntuacion"
  )

# Generar boxplot para cada variable seleccionada
ggplot(datos_largos, aes(x = Variable, y = Puntuacion, fill = Variable)) +
  geom_boxplot() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1), axis.title.x = element_blank()) +
  labs(title = "Distribución de Puntuaciones para Empleados en Desacuerdo con la Permanencia", 
       y = "Puntuación") +
  scale_fill_brewer(palette = "Set3")  # Usar una paleta de colores adecuada para distinguir variables

form_satisfaccion$edad <- as.numeric(as.character(form_satisfaccion$edad))
desacuerdo_permanencia <- form_satisfaccion %>%
  filter(permanencia_form_futuro %in% c(1, 2))

# Diagrama de dispersión para ver la relación entre 'edad' y 'personas_dependientes'
ggplot(form_satisfaccion, aes(x = edad, y = personas_dependientes)) +
  geom_point(color = "lightgrey") +
  geom_point(data = desacuerdo_permanencia, aes(x = edad, y = personas_dependientes), alpha = 0.6, color = "blue") +
  theme_minimal() +
  scale_x_continuous() + # Asumimos que la edad es numérica y ya no hay etiquetas específicas
  ggtitle("Comparación de Edad y Personas Dependientes (Filtrado por Poca Permanencia)") +
  xlab("Edad") +
  ylab("Personas Dependientes")

# Filtrar para obtener solo aquellos en desacuerdo con la permanencia a futuro (valor 1 o 2)
desacuerdo_permanencia <- form_satisfaccion %>% 
  filter(permanencia_form_futuro %in% c(1, 2))

# Obtener el conteo de cada razón de entrada y ordenarlo de mayor a menor
conteo_razon <- desacuerdo_permanencia %>%
  count(razon_entrada) %>%
  arrange(desc(n))

# Crear el gráfico de barras horizontal con barra más grande arriba
ggplot(conteo_razon, aes(x = reorder(razon_entrada, n), y = n, fill = n)) +
  geom_bar(stat = "identity") +
  scale_fill_gradient(low = "lightblue", high = "darkblue") +
  labs(y = "Razón de Entrada", x = "Conteo", title = "Conteo de Razón de Entrada para Desacuerdo con Permanencia") +
  theme_minimal() +
  theme(axis.text.y = element_text(hjust = 1),
        legend.position = "none") +
  coord_flip()  # Girar el gráfico para orientación horizontal

Situación Problema 2: Predicción de Demanda

¿Cuáles son los patrones históricos de demanda de empaques de cartón para autopartes en los mercados objetivo de la empresa FORM, y cómo varían estos patrones según la temporada, el tipo de autoparte, y las regiones geográficas?

# Agrupar las ventas por cuarto
ventas_por_quarter <- ventas_vehiculos %>%
  group_by(Fecha) %>%
  summarise(VEH_HIBRIDAS = sum(VEH_HIBRIDAS), .groups = 'drop')

# Gráfico para exportaciones
p1 <- ggplot(exp_vehiculos, aes(x = Fecha, y = trade_value)) +
  geom_line(color = "blue") +
  labs(title = "Exportaciones por Cuarto", y = "Valor de Exportaciones") +
  theme_minimal()

# Gráfico para ventas de vehículos híbridos
p2 <- ggplot(ventas_por_quarter, aes(x = Fecha, y = VEH_HIBRIDAS)) +
  geom_line(color = "green") +
  labs(title = "Ventas de Vehículos", y = "Número de Vehículos") +
  theme_minimal()

# Arreglar los gráficos lado a lado para comparar visualmente
p1 + p2 + plot_layout(guides = 'collect') & theme(legend.position = "bottom")
## Warning: The `trans` argument of `continuous_scale()` is deprecated as of ggplot2 3.5.0.
## ℹ Please use the `transform` argument instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

# Preparar los datos para descomposición
exp_ts <- ts(exp_vehiculos$trade_value, frequency = 4) # Frecuencia trimestral
ventas_ts <- ts(ventas_por_quarter$VEH_HIBRIDAS, frequency = 4) # Frecuencia trimestral

# Descomposición STL de las exportaciones
exp_decomp <- stl(exp_ts, s.window = "periodic")
plot(exp_decomp)

# Descomposición STL de las ventas de vehículos híbridos
ventas_decomp <- stl(ventas_ts, s.window = "periodic")
plot(ventas_decomp)

⁠¿Cómo impactan los lanzamientos de nuevos modelos de vehículos y las tendencias en la industria automotriz en la demanda de diferentes tipos de empaques de cartón para autopartes?

mx_vehicle_exports_summary <- exp_vehiculos_total %>%
  group_by(Año, Segmento) %>%
  summarise(Cantidad_Total = sum(Cantidad, na.rm = TRUE))

# Definir la paleta de colores personalizada
colores <- c("#2D3250", "#435585", "#7077A1", "#F6B17A", "#9EC8B9", "#BE3144")

# Asegurarse de que hay suficientes colores para los segmentos
# Repetir la paleta si hay más segmentos que colores
n_segmentos <- length(unique(mx_vehicle_exports_summary$Segmento))
if (n_segmentos > length(colores)) {
  colores <- rep(colores, length.out = n_segmentos)
}

# Gráfico de líneas con la paleta de colores personalizada
ggplot(mx_vehicle_exports_summary, aes(x = Año, y = Cantidad_Total, color = Segmento, group = Segmento)) + 
  geom_line() + # Dibuja líneas
  geom_point() + # Añade puntos en cada dato
  scale_color_manual(values = colores) + # Usa la paleta de colores definida
  theme_minimal() + # Usa un tema minimalista
  labs(title = "Evolución de la Exportación de Segmento de Vehículo a lo Largo de los Años",
       x = "Año",
       y = "Cantidad Total") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

⁠¿Cuál ha sido el efecto de las campañas de marketing y las actividades promocionales de la empresa FORM sobre la demanda de sus productos en el pasado?

# Sin Información Suficiente

⁠¿Cómo impactan algunas variables externas de carácter macroeconómico a las ventas de la empresa?

# Sin Información Suficiente

Pronosticar el evento de Nearshoring.

Bases de Datos de Nearshoring

setwd("../databases/nearshoring")
df=read.csv("quarter_economic_data.csv")

summary(df)
##       Year         Quarter      New_FDI_Inflows Exchange_Rate  
##  Min.   :2006   Min.   :1.000   Min.   :-2433   Min.   :10.82  
##  1st Qu.:2010   1st Qu.:1.000   1st Qu.: 1934   1st Qu.:12.65  
##  Median :2014   Median :2.000   Median : 2605   Median :13.65  
##  Mean   :2014   Mean   :2.478   Mean   : 3001   Mean   :15.59  
##  3rd Qu.:2018   3rd Qu.:3.000   3rd Qu.: 3750   3rd Qu.:19.26  
##  Max.   :2023   Max.   :4.000   Max.   :15445   Max.   :21.60  
##                                                                
##  new_fdi_inflows_mxn log_new_fdi_inflows_mxn new_foreign_businesses
##  Min.   :-37081      Min.   :-10.52          Min.   : 1.000        
##  1st Qu.: 33164      1st Qu.: 10.41          1st Qu.: 5.000        
##  Median : 46617      Median : 10.75          Median : 8.000        
##  Mean   : 51775      Mean   : 10.10          Mean   : 8.145        
##  3rd Qu.: 65069      3rd Qu.: 11.08          3rd Qu.:11.000        
##  Max.   :237466      Max.   : 12.38          Max.   :21.000        
##                                                                    
##  Población_Economicamente_Activa Poblacion_ocupada_industria_manufacturera
##  Min.   :2601760                 Min.   :13942848                         
##  1st Qu.:3404623                 1st Qu.:15463066                         
##  Median :3433560                 Median :16917276                         
##  Mean   :3440431                 Mean   :16696687                         
##  3rd Qu.:3525446                 3rd Qu.:17975390                         
##  Max.   :3597380                 Max.   :19516476                         
##  NA's   :20                      NA's   :20                               
##  Poblacion_ocupada   Tasa_de_ocupacion_industria_manufacturera
##  Min.   : 89430135   Min.   : 928.3                           
##  1st Qu.: 96999416   1st Qu.:1002.1                           
##  Median :102344068   Median :1040.2                           
##  Mean   :102769315   Mean   :1028.8                           
##  3rd Qu.:107429516   3rd Qu.:1062.1                           
##  Max.   :116984252   Max.   :1082.7                           
##  NA's   :20          NA's   :20
str(df)
## 'data.frame':    69 obs. of  11 variables:
##  $ Year                                     : int  2006 2006 2006 2006 2007 2007 2007 2007 2008 2008 ...
##  $ Quarter                                  : int  1 2 3 4 1 2 3 4 1 2 ...
##  $ New_FDI_Inflows                          : num  897 2110 1284 2678 3108 ...
##  $ Exchange_Rate                            : num  10.8 10.9 10.9 10.9 10.9 ...
##  $ new_fdi_inflows_mxn                      : num  15471 36790 22338 46617 52252 ...
##  $ log_new_fdi_inflows_mxn                  : num  9.65 10.51 10.01 10.75 10.86 ...
##  $ new_foreign_businesses                   : int  10 8 10 13 4 21 7 5 7 6 ...
##  $ Población_Economicamente_Activa          : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ Poblacion_ocupada_industria_manufacturera: num  NA NA NA NA NA NA NA NA NA NA ...
##  $ Poblacion_ocupada                        : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ Tasa_de_ocupacion_industria_manufacturera: num  NA NA NA NA NA NA NA NA NA NA ...
# Calculamos el número de NA por columna
nas_por_columna <- sapply(df, function(x) sum(is.na(x)))

# Filtramos las columnas que tienen 7 o más NA para eliminarlas
columnas_para_eliminar <- names(nas_por_columna[nas_por_columna >= 7])
df <- df %>% select(-one_of(columnas_para_eliminar))

# Para las columnas restantes, imputamos los NA con la mediana
df <- df %>% mutate(across(.cols = where(~ sum(is.na(.)) < 7), 
                           .fns = ~ ifelse(is.na(.), median(., na.rm = TRUE), .)))

Se realizó una imputación de las variables y se eliminaron aquellas con demasiados valores NAS faltantes.

Analisis de la Base de Nearshoring

summary(df)
##       Year         Quarter      New_FDI_Inflows Exchange_Rate  
##  Min.   :2006   Min.   :1.000   Min.   :-2433   Min.   :10.82  
##  1st Qu.:2010   1st Qu.:1.000   1st Qu.: 1934   1st Qu.:12.65  
##  Median :2014   Median :2.000   Median : 2605   Median :13.65  
##  Mean   :2014   Mean   :2.478   Mean   : 3001   Mean   :15.59  
##  3rd Qu.:2018   3rd Qu.:3.000   3rd Qu.: 3750   3rd Qu.:19.26  
##  Max.   :2023   Max.   :4.000   Max.   :15445   Max.   :21.60  
##  new_fdi_inflows_mxn log_new_fdi_inflows_mxn new_foreign_businesses
##  Min.   :-37081      Min.   :-10.52          Min.   : 1.000        
##  1st Qu.: 33164      1st Qu.: 10.41          1st Qu.: 5.000        
##  Median : 46617      Median : 10.75          Median : 8.000        
##  Mean   : 51775      Mean   : 10.10          Mean   : 8.145        
##  3rd Qu.: 65069      3rd Qu.: 11.08          3rd Qu.:11.000        
##  Max.   :237466      Max.   : 12.38          Max.   :21.000
dataf=df

data2 <- df %>% select(Year, Quarter, New_FDI_Inflows)
data2$Fecha <- as.Date(paste(data2$Year, data2$Quarter), format = "%Y %B")

time_serie <- ts(data2$New_FDI_Inflows, start = c(2006, 1), frequency = 4)

print(time_serie)
##          Qtr1     Qtr2     Qtr3     Qtr4
## 2006   896.56  2110.38  1284.01  2677.70
## 2007  3108.22  2560.70  6059.17  6298.70
## 2008  2502.17  1915.81  4039.98  4595.51
## 2009  2984.47  2254.08  1056.01  4713.82
## 2010  2947.54  6678.89  2259.95  3749.87
## 2011  3058.29  2091.13  2604.85  1944.86
## 2012  1493.80  2111.70  2401.90 -1691.33
## 2013   749.06 15444.59   262.28  5582.68
## 2014  2427.14 -2433.24   441.89  5326.99
## 2015  4406.85  2816.75  4501.10  1724.29
## 2016  3850.77  1460.80  1550.18  4129.80
## 2017  2780.67  3134.15  3570.25  2454.70
## 2018  1934.09  2292.64  4226.74  2869.82
## 2019  2584.06  2406.22  4959.36  3579.50
## 2020  2603.81   799.40  1606.59  1731.87
## 2021  2250.76  3657.32  4149.31  3607.11
## 2022  8823.96  3664.91  2653.16  2817.87
## 2023   931.69

Se convirtió la variable de Año en el formato adecuado de fecha.

plot(time_serie, main = "IED quarter", xlab = "Year quarter", ylab = "IED")

Podemos ver que el gráfico presenta un claro componente de estacionalidad y puede haber cierta estacionariedad, sin embargo, se ve una tendencia ascendente a lo largo de toda la serie de tiempo, por lo que es necesario aplicar diversas pruebas para comprender mejor nuestra serie de tiempo.

descompose<-decompose(time_serie)
plot(descompose)

En el gráfico anterior podemos observar una ligera tendencia en toda la serie temporal como se describió anteriormente, esto podría afectar la presencia de estacionariedad. Por otro lado, se evidencia el componente estacional, que aumenta en algunos trimestres de cada período. Esto se puede explicar en el contexto de la variable dependiente con estacionalidades en la demanda de bienes y servicios, eventos económicos como ferias comerciales o temporadas de impuestos. , o incluso patrones estacionales en la disponibilidad de recursos naturales.

Todo esto hace que en algunas partes de cada año la IED aumente y disminuya periódicamente. Respecto al componente aleatorio residual, se observa cierto ruido en las series temporales, especialmente en el período 2013-2015 y 2020 a 2022. Esto se debe a variaciones en la serie temporal que no pueden explicarse con componentes de estacionalidad o tendencias en la serie temporal. Esto, en un contexto real, se puede explicar con fenómenos con las reformas constitucionales del presidente Enrique Peña Nieto en 2013 y la pandemia de COVID-19 a partir de 2020.

# The stationarity of the series is checked with the following ADF test.
adf.test(time_serie)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  time_serie
## Dickey-Fuller = -5.631, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary

El resultado de la Prueba Aumentada de Dickey-Fuller (ADF) con un valor p de 0.01 (menor a 0.05) indica que la serie temporal “time_series” es estacionaria, lo que significa que no muestra tendencias en el tiempo.

acf(time_serie,main="Significant Autocorrelations") 

Podemos observar que la serie no muestra de autocorrelación serial, ya que en los periodos la función de autocorrelación no excede las líneas de significancia.

Modelo Arma Calculado

summary(arma<-arma(diff(time_serie)),order=c(1,1))
## 
## Call:
## arma(x = diff(time_serie))
## 
## Model:
## ARMA(1,1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -4043.9  -454.3   152.0  1327.9 12087.5 
## 
## Coefficient(s):
##            Estimate  Std. Error  t value Pr(>|t|)
## ar1          0.1571          NA       NA       NA
## ma1         -1.1888          NA       NA       NA
## intercept  109.8050          NA       NA       NA
## 
## Fit:
## sigma^2 estimated as 4774485,  Conditional Sum-of-Squares = 330433746,  AIC = 1244.73
plot(arma)

Estos coeficientes indican una correlación positiva débil con el valor anterior y una correlación negativa fuerte con el error en el período anterior, respectivamente. Además, se ha incluido un término de interceptación con un valor estimado de 109.8050

Los residuos del modelo tienen una varianza estimada (sigma^2) de 4774485 y los resultados del ajuste muestran un AIC muy alto.

Modelo Arima con Log y Diff Calculado

summary(arima<-Arima(diff(log((time_serie))),order=c(1,1,1))) 
## Series: diff(log((time_serie))) 
## ARIMA(1,1,1) 
## 
## Coefficients:
##           ar1      ma1
##       -0.6977  -1.0000
## s.e.   0.0904   0.0481
## 
## sigma^2 = 0.5655:  log likelihood = -73.89
## AIC=153.78   AICc=154.17   BIC=160.4
## 
## Training set error measures:
##                       ME      RMSE       MAE      MPE     MAPE      MASE
## Training set -0.05654218 0.7341827 0.5578686 71.55558 166.8534 0.7016035
##                     ACF1
## Training set -0.02718879
plot(arima)

El coeficiente autorregresivo (AR1) es -0,6977 y el coeficiente de media móvil (MA1) es -1,0000. Estos coeficientes indican que el valor actual de la serie temporal logarítmicamente diferenciada está correlacionado negativamente con su valor anterior y con el error en el período anterior.

La varianza estimada del modelo (sigma^2) es 0,0.5655. El valor logarítmico de verosimilitud es -73.89, y los criterios de información, como el AIC (Akaike Information Criterion), el AIC corregido (AICc) y el BIC (Bayesian Information Criterion), indican que este modelo podría ser apropiado para la serie temporal.

Pruebas de Diagnostico en la Data

Modelo Arma

arma_residuals<-arma$residuals
Box.test(arma_residuals,lag=1,type="Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  arma_residuals
## X-squared = 3.2686, df = 1, p-value = 0.07062

El valor de p obtenido en la prueba de Box-Ljung (0,07) es mayor que el valor de p máximo comúnmente utilizado que es 0,05. Esto significa que no se encontró evidencia significativa de autocorrelación en los residuos, ya que el valor p es mayor que 0,05, lo que respalda la validez del modelo en términos de autocorrelación.

#Testing residuals
suppressWarnings({
arma$residuals <- na.omit(arma$residuals)
adf.test(arma$residuals)
})
## 
##  Augmented Dickey-Fuller Test
## 
## data:  arma$residuals
## Dickey-Fuller = -6.32, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary

El valor de p de 0,01, inferior al umbral de 0,05, indica una fuerte evidencia contra la hipótesis nula de no estacionariedad. Esto significa que es poco probable que los residuos sean no estacionarios.

hist(arma$residuals)

Se aprecia relativa normalidad en los residuales.

Modelo Arima

arima_residuals<-arima$residuals
Box.test(arima_residuals,lag=1,type="Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  arima_residuals
## X-squared = 0.049564, df = 1, p-value = 0.8238

El valor de p obtenido en la prueba de Box-Ljung (0,8) es mayor que el valor de p máximo comúnmente utilizado que es 0,05. Esto significa que no se encontró evidencia significativa de autocorrelación en los residuos, ya que el valor p es mayor que 0,05, lo que respalda la validez del modelo en términos de autocorrelación.

residuals_ts <- arima$residuals

# Interpolar los valores NA
residuals_clean <- na.approx(residuals_ts)

suppressWarnings({
  adf_test_result <- adf.test(residuals_clean)
})

# Ver el resultado
print(adf_test_result)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  residuals_clean
## Dickey-Fuller = -2.9227, Lag order = 4, p-value = 0.2004
## alternative hypothesis: stationary

El valor de p de 0,01, inferior al umbral de 0,05, indica una fuerte evidencia contra la hipótesis nula de no estacionariedad. Esto significa que es poco probable que los residuos sean no estacionarios.

hist(arima$residuals)

Se aprecia normalidad en los residuales del modelo 2.

Debido a métricas como el AIC y a las pruebas de diagnóstico, el modelo 2 es elegido como el más apropiado.

Forecast de Nearshoring

suppressWarnings({
arima_restauracion<-exp(arima$fitted) # The variables are transformed back to the originals (if log is applied, the exponential must be applied (it is the opposite))
vector2 =c(arima_restauracion) #reverting "log" operation using "exp"
original2 <-c(time_serie) #Converting into a vector.
restauracion2 = vector2+original2 #reverting "diff" operation summing the original values to the differences.
ts2 <- ts(restauracion2, start = 1, end = length(restauracion2), frequency = 4) #Make time series
})
# Forecast (ARIMA)
arima_forecast<-forecast(ts2,h=5)
arima_forecast
##       Point Forecast     Lo 80    Hi 80     Lo 95    Hi 95
## 24 Q4       3036.064 1121.9856 4950.143 108.73368 5963.394
## 25 Q1       3742.547 1383.0682 6102.026 134.03557 7351.058
## 25 Q2       2318.412  856.7754 3780.049  83.03154 4553.793
## 25 Q3       3128.604 1156.1840 5101.025 112.04764 6145.161
## 25 Q4       3036.064 1121.9853 4950.143 108.73322 5963.395
plot(arima_forecast)

autoplot(arima_forecast)

En el pronóstico realizado para la Inversión Extranjera Directa (IED) relacionada con el fenómeno del nearshoring, se observan tendencias y variaciones interesantes para los próximos cinco trimestres. La predicción se presenta con intervalos de confianza del 80% y del 95%, lo que nos permite entender la incertidumbre asociada con cada estimación de punto.

Para el cuarto trimestre del año 24, el pronóstico de punto estima una IED de 3,036.064 millones de dólares. Los intervalos de confianza sugieren que, con un 80% de confianza, la IED podría variar entre 1,121.986 y 4,950.143 millones de dólares. Ampliando la certeza al 95%, el rango se extiende desde 108.734 hasta 5,963.394 millones de dólares, indicando una mayor incertidumbre en las estimaciones.

En el primer trimestre del año 25, se espera un aumento en la IED hasta los 3,742.547 millones de dólares. El intervalo de confianza del 80% se sitúa entre 1,383.068 y 6,102.026 millones de dólares, mientras que el intervalo al 95% se amplía desde 134.036 hasta 7,351.058 millones de dólares, reflejando nuevamente la incertidumbre en el pronóstico.

Para el segundo trimestre del año 25, el pronóstico muestra una disminución en la IED a 2,318.412 millones de dólares. Los intervalos de confianza para este trimestre son más estrechos, con el intervalo del 80% variando entre 856.775 y 3,780.049 millones de dólares, y el del 95% entre 83.032 y 4,553.793 millones de dólares.

En el tercer trimestre del año 25, se prevé un repunte en la IED a 3,128.604 millones de dólares, con intervalos de confianza similares a los observados en el cuarto trimestre del año 24.

Finalmente, para el cuarto trimestre del año 25, el pronóstico vuelve a estimar una IED de 3,036.064 millones de dólares, con intervalos de confianza prácticamente idénticos a los del cuarto trimestre del año 24.

Este análisis de pronóstico muestra una variabilidad significativa en la IED esperada relacionada con el nearshoring a lo largo de los próximos cinco trimestres.

Principales Hallazgos

Incremento de Nearshoring

  • Previsión positiva: La tendencia creciente del nearshoring es esperada para impulsar favorablemente las ventas de FORM, según el modelo ARIMA que pronostica la Inversión Extranjera Directa.

Tendencias en Industrias Clave

  • Automotriz y Cartón: Ambas industrias muestran tendencias positivas. Las ventas y exportaciones nacionales reflejan un incremento constante, con la industria automotriz exhibiendo estacionalidad con picos en el tercer trimestre, lo que sugiere una correlación directa entre ventas y exportaciones. Esto presenta una perspectiva optimista para la demanda de productos de FORM.

Factores de Rotación de Personal

  • Principales causantes de baja: La ubicación de la empresa, altas temperaturas y la insuficiencia de herramientas son identificados como factores críticos detrás de la baja de colaboradores. Específicamente, las molestias por temperatura afectan al 33% de los encuestados, seguido de un 20% en desacuerdo con las prestaciones y un 19% que señala la falta de herramientas adecuadas.
  • Análisis de Permanencia: La determinación de factores relacionados con la baja intención de permanencia en FORM muestra que el ofrecimiento de herramientas adecuadas y condiciones de trabajo óptimas son áreas clave de mejora.
  • Perfil del trabajador insatisfecho: Menores de 30 años con hasta dos personas dependientes, citando la ubicación de la empresa como la razón principal de entrada.

Demanda de Autopartes y Empaques

  • Vehículos Eléctricos: La tendencia al alza en la venta de vehículos eléctricos sugiere la necesidad de adaptar los tipos de empaques para estas autopartes, representando una oportunidad de innovación para FORM.

Tendencias de Bajas de Personal

  • Incremento y género: Hay un incremento notable en las bajas en comparación con el año anterior, con una mayor incidencia en mujeres. Además, se observa un aumento en las bajas conforme avanza el año, especialmente en abril y febrero.

Insights Adicionales

  • La realización de encuestas por parte de FORM ha permitido identificar con precisión los factores de satisfacción e insatisfacción laboral, subrayando la importancia de atender estas áreas para mejorar la retención del personal.

Referencias

  1. D&B Hoovers is Your Sales Accelerator – Dun & Bradstreet. (s. f.). Recuperado 16 de marzo de 2024, de https://www.dnb.com/products/dnb-hoovers.html

  2. World Bank Group - International Development, Poverty, & Sustainability. (s. f.). World Bank. Recuperado 16 de marzo de 2024, de https://www.worldbank.org/en/home

  3. Smithers - Innovate with confidence. (s. f.). Smithers. Recuperado 16 de marzo de 2024, de https://www.smithers.com/home

  4. Statista. (s. f.). Statista - the statistics portal. Recuperado 16 de marzo de 2024, de https://www.statista.com/

  5. MexicoIndustry. (s. f.). Incrementará 8% el sector automotriz en 2024*. MexicoIndustry. Recuperado 16 de marzo de 2024, de https://mexicoindustry.com/noticia/incrementara-8-el-sector-automotriz-en-2024

  6. Newsroom Infobae. (2023, 12 abril). Industria automotriz en México espera más empleos por electromovilidad. Infobae*. Recuperado 16 de marzo de 2024, de https://www.infobae.com/america/agencias/2023/04/12/industria-automotriz-en-mexico-espera-mas-empleos-por-electromovilidad/

LS0tCnRpdGxlOiAnRXZpZGVuY2UgMSA6IEZPUk0gU3R1ZHkgQ2FzZScKYXV0aG9yOiAiRGF2aWQgRG9taW5ndWV6IC0gQTAxNTcwOTc1IgpkYXRlOiAiMjAyNC0wNC0wNSIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKICAgIHRoZW1lOiBjb3NtbwotLS0KCiFbRk9STSBCQU5ORVJdKC9Vc2Vycy9kYXZpZGRydW1zMTgwL1RlYy9DYXNlX1N0dWR5X0Zvcm0vc3JjL2Zvcm0uanBnKQoKIyAqKkZhc2UgSSA6IENvbnRleHRvKioKCiMjIExlY3R1cmFzIFN1Z2VyaWRhcwojIyMjIFdoYXQgaXMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcz8KaHR0cHM6Ly93d3cuaWJtLmNvbS90b3BpY3MvZXhwbG9yYXRvcnktZGF0YS1hbmFseXNpcwoKIyMjIyBXaGF0IGlzIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXM/Cmh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS9leHBsb3JhdG9yeS1kYXRhLWFuYWx5c2lzLThmYzFjYjIwZmQxNQoKIyMjIyBXaGF0IGlzIERlc2NyaXB0aXZlIEFuYWx5dGljcz8gNSBFeGFtcGxlcwpodHRwczovL29ubGluZS5oYnMuZWR1L2Jsb2cvcG9zdC9kZXNjcmlwdGl2ZS1hbmFseXRpY3MKCiMjIyMgTmVhcnNob3Jpbmcgd2lsbCBNYWtlIE1leGljbyDigJhUaGUgTW90b3LigJ0gb2YgVVMgRWxlY3RyaWMgVmVoaWNsZQpJbmR1c3RyeQpodHRwczovL3d3dy5ibG9vbWJlcmdsaW5lYS5jb20vZW5nbGlzaC9uZWFyc2hvcmluZy13aWxsLW1ha2UtbWV4aWNvLXRoZS1tb3Rvci1vZi11cy1lbGVjdHJpYy12ZWhpY2xlLWluZHVzdHJ5LwoKIyMjIyBOZWFyc2hvcmluZzogTG9zIFJldG9zIHkgT3BvcnR1bmlkYWRlcyBxdWUgdGllbmUgcGFyYSBNw6l4aWNvIGVuCjIwMjQuCmh0dHBzOi8vY29uZWN0YS50ZWMubXgvZXMvbm90aWNpYXMvbmFjaW9uYWwvZW1wcmVuZGVkb3Jlcy9uZWFyc2hvcmluZy1sb3MtcmV0b3MteS1vcG9ydHVuaWRhZGVzLXF1ZS10aWVuZS1wYXJhLW1leGljby1lbi0yMDI0Izp+OnRleHQ9RWwlMjBuZWFyc2hvcmluZyUyMGVzJTIwdW5hJTIwZXN0cmF0ZWdpYSxlbiUyMHVuJTIwcGElQzMlQURzJTIwY2VyY2FubyUyMGdlb2dyJUMzJUExZmljYW1lbnRlCgojIyBMaWJyZXLDrWFzIG5lY2VzYXJpYXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoaW1wdXRlVFMpICMgUmVsbGVuYXIgZGF0b3MgZmFsdGFudGVzCmxpYnJhcnkoeHRzKSAjIE1hbmlwdWxhY2nDs24gZGUgc2VyaWVzIHRlbXBvcmFsZXMKbGlicmFyeSh6b28pICMgU2lzdGVtYXMgZGUgc2VyaWVzIHRlbXBvcmFsZXMKbGlicmFyeSh0c2VyaWVzKSAjIEFuw6FsaXNpcyBkZSBzZXJpZXMgdGVtcG9yYWxlcwpsaWJyYXJ5KHN0YXRzKSAjIEZ1bmNpb25lcyBlc3RhZMOtc3RpY2FzIGLDoXNpY2FzCmxpYnJhcnkoZm9yZWNhc3QpICMgUHJlZGljY2nDs24gZGUgc2VyaWVzIHRlbXBvcmFsZXMKbGlicmFyeShhc3RzYSkgIyBBbsOhbGlzaXMgZGUgc2VyaWVzIHRlbXBvcmFsZXMgYXBsaWNhZG8KbGlicmFyeShjb3JycGxvdCkgIyBWaXN1YWxpemFjacOzbiBkZSBtYXRyaWNlcyBkZSBjb3JyZWxhY2nDs24KbGlicmFyeSh3b3JkY2xvdWQpICMgQ3JlYXIgbnViZXMgZGUgcGFsYWJyYXMKbGlicmFyeSh0aWR5dGV4dCkgIyBBbsOhbGlzaXMgZGUgdGV4dG8gY29uIHRpZHkgZGF0YQpsaWJyYXJ5KEFFUikgIyBBbsOhbGlzaXMgZWNvbm9tw6l0cmljbyBjb24gUgpsaWJyYXJ5KHZhcnMpICMgTW9kZWxvcyBWQVIgeSBTVkFSCmxpYnJhcnkoZHlubG0pICMgTW9kZWxvcyBsaW5lYWxlcyBkaW7DoW1pY29zCmxpYnJhcnkobUZpbHRlcikgIyBGaWx0cm9zIHBhcmEgc2VyaWVzIHRlbXBvcmFsZXMKbGlicmFyeShUU3N0dWRpbykgIyBIZXJyYW1pZW50YXMgaW50ZXJhY3RpdmFzIHNlcmllcyB0ZW1wb3JhbGVzCmxpYnJhcnkodGlkeXZlcnNlKSAjIENvbGVjY2nDs24gZGUgcGFxdWV0ZXMgZGUgZGF0b3MgdGlkeQpsaWJyYXJ5KHNhcmltYSkgIyBNb2RlbG9zIFNBUklNQQpsaWJyYXJ5KHJlYWRyKSAjIExlZXIgYXJjaGl2b3MgcGxhbm9zCmxpYnJhcnkocmVhZHhsKSAjIExlZXIgYXJjaGl2b3MgRXhjZWwKbGlicmFyeShoZWF0bWFwbHkpICMgSGVhdG1hcHMgaW50ZXJhY3Rpdm9zCmxpYnJhcnkoZHBseXIpICMgTWFuaXB1bGFjacOzbiBkZSBkYXRvcwpsaWJyYXJ5KGdncGxvdDIpICMgU2lzdGVtYSBkZSBncsOhZmljb3MKbGlicmFyeShwc3ljaCkgIyBQcm9jZWRpbWllbnRvcyBwc2ljb23DqXRyaWNvcwpsaWJyYXJ5KHRpZHlyKSAjIFJlb3JnYW5pemFjacOzbiBkZSBkYXRvcwpsaWJyYXJ5KHJlYWR0ZXh0KSAjIExlZXIgYXJjaGl2b3MgZGUgdGV4dG8KbGlicmFyeShzeXV6aGV0KSAjIEFuw6FsaXNpcyBkZSBzZW50aW1pZW50b3MKbGlicmFyeShSQ29sb3JCcmV3ZXIpICMgUGFsZXRhcyBkZSBjb2xvcmVzCmxpYnJhcnkodG0pICMgTWluZXLDrWEgZGUgdGV4dG8KbGlicmFyeShjYXJldCkgIyBFbnRyZW5hbWllbnRvIGRlIG1vZGVsb3MgcHJlZGljdGl2b3MKbGlicmFyeShNQVNTKSAjIE3DqXRvZG9zIGVzdGFkw61zdGljb3MgYWRpY2lvbmFsZXMKbGlicmFyeShycGFydCkgIyBNb2RlbG9zIGRlIHBhcnRpY2nDs24gcmVjdXJzaXZhCmxpYnJhcnkocnBhcnQucGxvdCkgIyBHcsOhZmljb3MgcGFyYSBycGFydApsaWJyYXJ5KHBhcnR5KSAjIE1vZGVsb3MgYmFzYWRvcyBlbiDDoXJib2xlcwpsaWJyYXJ5KGdtb2RlbHMpICMgSGVycmFtaWVudGFzIGRlIG1vZGVsYWRvCmxpYnJhcnkoa25pdHIpICMgUmVwb3J0ZXMgZGluw6FtaWNvcwpsaWJyYXJ5KGNsdXN0ZXIpICMgTcOpdG9kb3MgZGUgYWdydXBhbWllbnRvCmxpYnJhcnkoZTEwNzEpICMgTWlzYyBmdW5jaW9uZXMgU1ZNCmxpYnJhcnkocFJPQykgIyBDdXJ2YXMgUk9DCmxpYnJhcnkoSVNMUikgIyBEYXRhIHNldHMgcGFyYSBhcHJlbmRpemFqZSBlc3RhZMOtc3RpY28KbGlicmFyeShncmlkRXh0cmEpICMgRGlzcG9zaWNpw7NuIGRlIG3Dumx0aXBsZXMgZ3LDoWZpY29zCmxpYnJhcnkoY2FyKSAjIFJlZ3Jlc2nDs24geSBBbm92YSBjb24gUgpsaWJyYXJ5KERhdGFFeHBsb3JlcikgIyBBdXRvbWF0aXphciBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvCmxpYnJhcnkocmFuZG9tRm9yZXN0KSAjIENsYXNpZmljYWNpw7NuIGNvbiByYW5kb20gZm9yZXN0CmxpYnJhcnkoY2xhc3MpICMgay12ZWNpbm9zIG3DoXMgY2VyY2Fub3MKbGlicmFyeShmYWN0b2V4dHJhKSAjIFZpc3VhbGl6YWNpw7NuIGRlIHJlc3VsdGFkb3MgZGUgY2x1c3RlcmluZwpsaWJyYXJ5KHB1cnJyKSAjIFByb2dyYW1hY2nDs24gZnVuY2lvbmFsCmxpYnJhcnkodmlyaWRpcykgIyBQYWxldGFzIGRlIGNvbG9yZXMgcGFyYSBncsOhZmljb3MKbGlicmFyeShzY2FsZXMpICMgRXNjYWxhZG8gZGUgZ3LDoWZpY29zCmxpYnJhcnkobHVicmlkYXRlKSAjIE1hbmlwdWxhY2nDs24gZGUgZmVjaGFzIHkgaG9yYXMKbGlicmFyeShwYXRjaHdvcmspICMgQ29tYmluYXIgZ2dwbG90MiBwbG90cwpsaWJyYXJ5KGphbmVhdXN0ZW5yKSAjIFRleHRvcyBkZSBKYW5lIEF1c3RlbgpsaWJyYXJ5KHJlc2hhcGUyKSAjIFJlZXN0cnVjdHVyYXIgZGF0b3MKbGlicmFyeSh0bWFwKSAjIENyZWFyIG1hcGFzCmxpYnJhcnkoc2YpICMgTWFuaXB1bGFjacOzbiBkZSBkYXRvcyBnZW9lc3BhY2lhbGVzCmBgYAoKIyMgQmFzZXMgZGUgRGF0b3MgCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnNldHdkKCIuLi9kYXRhYmFzZXMiKQoKZm9ybV9zYXRpc2ZhY2Npb24gPC0gcmVhZF9leGNlbCgiZm9ybS9FbmN1ZXN0YV9EYXRvc19GT1JNX0ZhbGwyMDIzLnhsc3giKQpmb3JtX2JhamFzID0gcmVhZF94bHN4KCJmb3JtL3RlbXBvcmFyeS9CRERfRk9STV9CQUpBUy0yMDIzLnhsc3giKQpjcF9ubCA8LSBzdF9yZWFkKCJnZW9fcmVmZXJlbmNlX19ubC9DUF9OTCIpCgpleHBfdmVoaWN1bG9zID0gcmVhZF9jc3YoImluZHVzdHJ5X2F1dG9zX214L2V4cG9ydGFjaW9uX3ZlaGljdWxvc19teC5jc3YiKQp2ZW50YXNfdmVoaWN1bG9zID0gcmVhZF9jc3YoImluZHVzdHJ5X2F1dG9zX214L214X3ZlbnRhX3ZlaGljdWxvcy5jc3YiKQpleHBfdmVoaWN1bG9zX3RvdGFsID0gcmVhZF9leGNlbCgiaW5kdXN0cnlfYXV0b3NfbXgvZXhwb3J0YWNpb25fdmVoaWN1bG9zLnhsc3giKQoKZm9ybV9yaCA9IHJlYWRfY3N2KCJmb3JtL0RhdG9zX0ZPUk1fUkhfRkoyMDI0LmNzdiIpCmZvcm1fdmVudGFzX2RldGFsbGUgPSByZWFkX2V4Y2VsKCJmb3JtL0RhdG9zX0ZPUk1fVmVudGFzX0ZKMjAyNC54bHN4IikKYGBgCgojIyBJbnRyb2R1Y2Npw7NuCgojIyMgUHJlZ3VudGFzIGRlIFJlZmxleGnDs24KCiMjIyMgwr9RdcOpIGVzIHVuIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgbG9zIGRhdG9zPwpFbCBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvIGRlIGxvcyBkYXRvcyBvIEVEQSBlcyB1biBwcm9jZXNvIGFuYWxpdGljbyBpbmljaWFsIGVuIGVsIGFuYWxpc2lzIGRlIGNvbmp1bnRvcyBkZSBkYXRvcyBxdWUgcGVybWl0ZSBvYnRlbmVyIHVuYSBjb21wcmVuc2nDs24gZGUgbGFzIGNhcmFjdGVyw61zdGljYXMgZnVuZGFtZW50YWxlcyBkZSBsb3MgZGF0b3MuIAoKRXN0byBzZSBwdWVkZSBoYWNlciBtZWRpYW50ZSByZXPDum1lbmVzIGVzdGFkw61zdGljb3MsIG1lZGlkYXMgZGVzY3JpcHRpdmFzLCB2aXN1YWxpemFjacOzbiBkZSBkYXRvcywgeSBsYSBpZGVudGlmaWNhY2nDs24gZGUgcGF0cm9uZXMgbyBhbm9tYWzDrWFzIGRlbnRybyBkZWwgY29uanVudG8gZGUgZGF0b3MgY29uIG1hdHJpY2VzIGRlIGNvcnJlbGFjacOzbiBvIHNjYXR0ZXIgcGxvdHMuIFN1IG9iamV0aXZvIHByaW5jaXBhbCBlcyBleHBsb3JhciB5IGVudGVuZGVyIGxhIG5hdHVyYWxlemEgZGUgbG9zIGRhdG9zIHBhcmEgaW5mb3JtYXIgbGFzIGV0YXBhcyBwb3N0ZXJpb3JlcyBkZWwgYW7DoWxpc2lzLgoKIyMjIyDCv0PDs21vIGNvbnRyaWJ1eWUgZWwgYW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBkZSBsb3MgZGF0b3MgYSBtZWpvcmFyIGVsIHByb2Nlc28geSBsb3MgcmVzdWx0YWRvcyBkZSBhbmFsw610aWNhIGRlc2NyaXB0aXZhPwpFbCBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvIGRlIGxvcyBkYXRvcyBjb250cmlidXllIHNpZ25pZmljYXRpdmFtZW50ZSBhIG1lam9yYXIgZWwgcHJvY2VzbyB5IGxvcyByZXN1bHRhZG9zIGRlIGxhIGFuYWzDrXRpY2EgZGVzY3JpcHRpdmEgZGUgdmFyaWFzIG1hbmVyYXMuIFByaW1lcm8sIGF5dWRhIGEgaWRlbnRpZmljYXIgbGFzIHRlbmRlbmNpYXMsIGNvcnJlbGFjaW9uZXMgeSBwYXRyb25lcyBvY3VsdG9zIHF1ZSBwdWVkZW4gc2VyIGltcG9ydGFudGVzIHBhcmEgbGEgY29tcHJlbnNpw7NuIGRlIGxvcyBkYXRvcy4gRXN0byBwZXJtaXRlIGZvcm11bGFyIGhpcMOzdGVzaXMgbcOhcyBwcmVjaXNhcyB5IGRpcmlnaXIgZWwgYW7DoWxpc2lzIGRlc2NyaXB0aXZvIHkgcG9zdGVyaW9yIChwcmVkaWN0aXZvIG8gcHJlc2NyaXB0aXZvKSBkZSBtYW5lcmEgbcOhcyBlZmVjdGl2YS4gCgpTZWd1bmRvLCBhbCBkZXNjdWJyaXIgZGF0b3MgYXTDrXBpY29zIG8gYW5vbWFsw61hcywgZWwgRURBIGFzZWd1cmEgbGEgY2FsaWRhZCB5IGxhIHByZWNpc2nDs24gZGUgbG9zIGRhdG9zIGFudGVzIGRlIHByb2NlZGVyIGNvbiBhbsOhbGlzaXMgbcOhcyBjb21wbGVqb3MsIGFzw60gY29tbyBpZGVudGlmaWNhciBsYSBuZWNlc2lkYWQgZGUgdHJhbnNmb3JtYWNpw7NuZXMgbmVjZXNhcmlhcyBwcmV2aWFzIGEgcmVhbGl6YXIgZWwgYW7DoWxpc2lzIEZpbmFsbWVudGUsIGZhY2lsaXRhIGxhIHNlbGVjY2nDs24gZGUgbGFzIHTDqWNuaWNhcyBlc3RhZMOtc3RpY2FzIG8gbW9kZWxvcyBkZSBkYXRvcyBtw6FzIGFkZWN1YWRvcyBhbCByZXZlbGFyIGxhIGVzdHJ1Y3R1cmEgeSBkaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcywgbG8gcXVlIGNvbmR1Y2UgYSBpbnNpZ2h0cyBtw6FzIHJlbGV2YW50ZXMgeSBhIGxhIHRvbWEgZGUgZGVjaXNpb25lcyBiYXNhZGEgZW4gZGF0b3MuCgojIyMgQW50ZWNlZGVudGVzIGRlIGxhIEVtcHJlc2EgRk9STQpMYSBlbXByZXNhIEZPUk0sIGNvbiBzZWRlIGVuIE3DqXhpY28sIHNlIGhhIGRlc3RhY2FkbyBlbiBlbCBkZXNhcnJvbGxvIGRlIGlubm92YWNpb25lcyBlbiBlbCBlbXBhcXVlIGRlIGF1dG9wYXJ0ZXMsIGVuZm9jw6FuZG9zZSBlbiBzb2x1Y2lvbmVzIHF1ZSBwZXJtaXRlbiByZWR1Y2lyIGVsIGVzcGFjaW8gbmVjZXNhcmlvIHBhcmEgYWxtYWNlbmFtaWVudG8geSBnZW5lcmFuZG8gYWhvcnJvcyBlbiBsb2fDrXN0aWNhLiBIYW4gaW50cm9kdWNpZG8gdW4gcHJvZHVjdG8gcGF0ZW50YWRvIGdsb2JhbG1lbnRlIHF1ZSBhdW1lbnRhIGxhIGNhcGFjaWRhZCBkZSBlbXBhcXVlIHkgcmVkdWNlIHNpZ25pZmljYXRpdmFtZW50ZSBlbCB1c28gZGUgbWF0ZXJpYSBwcmltYSwgbG8gY3VhbCB0YW1iacOpbiB0aWVuZSB1biBpbXBhY3RvIHBvc2l0aXZvIGVuIGVsIG1lZGlvIGFtYmllbnRlLgoKRGVzZGUgc3UgZnVuZGFjacOzbiBlbiAyMDExLCBGT1JNIGhhIGNyZWNpZG8gc2lnbmlmaWNhdGl2YW1lbnRlLCBjb21lbnphbmRvIGNvbiB1biBzb2xvIGNsaWVudGUgeSBzZWlzIGVtcGxlYWRvcywgeSBleHBhbmRpw6luZG9zZSBhIG3DoXMgZGUgMTUwIGNvbGFib3JhZG9yZXMgeSBhdGVuZGllbmRvIGEgbcOhcyBkZSAxNSBjbGllbnRlcyBhdXRvbW90cmljZXMuIEVudHJlIHN1cyBjbGllbnRlcyBzZSBlbmN1ZW50cmFuIG5vbWJyZXMgcHJvbWluZW50ZXMgY29tbyBEZW5zbywgTWFnbmEsIEludGVybmF0aW9uYWwgQXV0b21vdGl2ZSBDb21wb25lbnRzIHkgVmFycm9jIExpZ2h0aW5nIFN5c3RlbXMuCgpMYSBlc3BlY2lhbGl6YWNpw7NuIGRlIEZPUk0gZW4gZW1wYXF1ZXMgcGFyYSBhdXRvcGFydGVzIGRlbGljYWRhcyB5IGNvc3Rvc2FzIGxhIGhhIGxsZXZhZG8gYSBzZXIgcHJvdmVlZG9yIGRlIGFybWFkb3JhcyBkZSBwcmVzdGlnaW8gY29tbyBUZXNsYSwgQk1XIHkgTWVyY2VkZXMgQmVuei4gT2ZyZWNlbiBzb2x1Y2lvbmVzIHBlcnNvbmFsaXphZGFzIHF1ZSBhc2VndXJhbiBsYSBwcm90ZWNjacOzbiB5IGxhIGludGVncmlkYWQgZGUgbGFzIGF1dG9wYXJ0ZXMgZHVyYW50ZSBzdSB0cmFuc3BvcnRlLCBsbyBxdWUgZXMgY3J1Y2lhbCBwYXJhIHBpZXphcyBkZSBhY2FiYWRvIGRlbGljYWRvIG8gZXNwZWpvLgoKQ29uIHVuYSBwbGFudGEgZW4gQXBvZGFjYSwgTnVldm8gTGXDs24sIGxhIGVtcHJlc2EgaGEgZXN0YWJsZWNpZG8gdW4gw6FyZWEgZXNwZWNpYWxpemFkYSBwYXJhIGVtcGFxdWVzIHRlcm1vZm9ybWFkb3MsIGVzZW5jaWFsZXMgcGFyYSBlbCB0cmFuc3BvcnRlIGRlIHBpZXphcyBlbGVjdHLDs25pY2FzIHkgb3RyYXMgYXV0b3BhcnRlcyBzZW5zaWJsZXMgcXVlIHJlcXVpZXJlbiBjdWlkYWRvIGVzcGVjaWFsIHBhcmEgZXZpdGFyIGRhw7FvcyBkdXJhbnRlIGVsIHRyw6Fuc2l0by4KCkxhIGZpbG9zb2bDrWEgZGUgRk9STSBkZSByZWR1Y2lyIGVsIGVzcGFjaW8gZGUgYWxtYWNlbmFtaWVudG8sIGxhIG1hbm8gZGUgb2JyYSBwYXJhIGxhIGFkbWluaXN0cmFjacOzbiB5IGVsIGFybWFkbyBkZSBlbXBhcXVlcywganVudG8gY29uIGxhIHByb3RlY2Npw7NuIGRlbCBwcm9kdWN0bywgc2UgYWxpbmVhIGNvbiBsYSBkZW1hbmRhIGNyZWNpZW50ZSBkZSBsYSBpbmR1c3RyaWEgYXV0b21vdHJpeiBwb3IgZWZpY2llbmNpYSB5IHNvc3RlbmliaWxpZGFkIGVuIGxhcyBjYWRlbmFzIGRlIHN1bWluaXN0cm8uCgpMYXMgaW5ub3ZhY2lvbmVzIGRlIEZPUk0geSBzdSBlbmZvcXVlIGVuIGxhIHNvc3RlbmliaWxpZGFkIHkgZWZpY2llbmNpYSByZWZsZWphbiB1biBjb21wcm9taXNvIGNvbiBsYSBtZWpvcmEgY29udGludWEgeSBsYSBhZGFwdGFjacOzbiBhIGxhcyBuZWNlc2lkYWRlcyBjYW1iaWFudGVzIGRlbCBtZXJjYWRvIGF1dG9tb3RyaXosIGxvIHF1ZSBsZXMgaGEgcGVybWl0aWRvIG1hbnRlbmVyc2UgY29tcGV0aXRpdm9zIHkgcmVsZXZhbnRlcyBlbiB1biBzZWN0b3IgZW4gY29uc3RhbnRlIGV2b2x1Y2nDs24uIAoKIyMjIyBNaXNpw7NuIAoKVHJhbnNmb3JtYXIgbnVlc3RybyBlbnRvcm5vIHkgcmVzb2x2ZXIgcmV0b3MgaW5kdXN0cmlhbGVzIGRlIG51ZXN0cm9zIGNsaWVudGVzIGEgdHJhdsOpcyBkZSBsYSBjb2xhYm9yYWNpw7NuLCBwcm92b2NhbmRvIG51ZXZhcyBvcG9ydHVuaWRhZGVzIHF1ZSBwb3RlbmNpYW4gbnVlc3RybyBtb2RlbG8gZGUgbmVnb2NpbywgcGFyYSBhbGNhbnphciBudWVzdHJvcyBpZGVhbGVzLgoKIyMjIyBWaXNpw7NuCgpFbiAyMDMzIHNlcmVtb3MgdW5hIGRlIGxhcyBjaW5jbyBtZWpvcmVzIGNvbXBhw7HDrWFzIGRlIE3DqXhpY28gcXVlIGdlbmVyYW4gdmFsb3IgZGVudHJvIGRlIGxhIGNhZGVuYSBkZSBzdW1pbmlzdHJvIGRlIGxhcyBpbmR1c3RyaWFzIHF1ZSBtw6FzIHZhbG9yYW4gbGEgZm9ybWEgZW4gbGEgcXVlIHNlIHByb3RlZ2VuIHkgdHJhc2xhZGFuIGxhcyBjb3Nhcy4KCiMjIyMgT2JqZXRpdm8gRXN0cmF0w6lnaWNvCgrigJxBaG9yYSBlc3RhbW9zIHZvbHRlYW5kbyBhIGxvcyBFc3RhZG9zIFVuaWRvcywgeSBhaG9yYSBjb24gbGEgcG9zaWJpbGlkYWQgZGUgcXVlIFRlc2xhIGxsZWd1ZSBhIE51ZXZvIExlw7NuLCBjb24gbWF5b3Igc2VudGlkbyB2b2x0ZWFtb3MgaGFjaWEgYWxsw6EuIFNpIHRvZG9zIG51ZXN0cm9zIGNsaWVudGVzIHNvbiBhdXRvbW90cmljZXMgZSBpbnRlcm5hY2lvbmFsZXMgcG9yIHF1w6kgbm8gcHJvdmVlcmxvcyBlbiBFc3RhZG9zIFVuaWRvcywgZXN0YW1vcyB0cmFiYWphbmRvIGZ1ZXJ0ZSBwYXJhIGxvZ3Jhcmxv4oCdLiAtIEZlbGlwZSBGbG9yZXMgR2FyY8OtYQoKIyMjIENvbnRleHRvIGRlIGxhIEluZHVzdHJpYQoKIyMjIyBBbsOhbGlzaXMgZGUgbGEgSW5kdXN0cmlhIChjYXJ0w7NuLCBhdXRvcGFydGVzLCBhdXRvbW90cml6KQoKUGFyYSBlbCBjYXNvIGRlIE3DqXhpY28geSBFLlUuQS4gKGluY2x1aXIgMy01IGdyw6FmaWNvcyB1c2FuZG8gUlwqKSB1c2FuZG8KZnVlbnRlcyBkZSBkYXRvcyBzZWN1bmRhcmlhcwoKRWwgbWVyY2FkbyBhdXRvbW90cml6IGVuIE3DqXhpY28gY29uc3RpdHV5ZSB1biBzZWN0b3Igdml0YWwgcGFyYSBsYSBlY29ub23DrWEgZGVsIHBhw61zLCBubyBzb2xvIHBvciBzdSBzaWduaWZpY2F0aXZhIGNvbnRyaWJ1Y2nDs24gYWwgUHJvZHVjdG8gSW50ZXJubyBCcnV0byAoUElCKSBzaW5vIHRhbWJpw6luIHBvciBzdSBwYXBlbCBlbiBsYSBjcmVhY2nDs24gZGUgZW1wbGVvcyB5IGVuIGVsIGZvbWVudG8gZGUgbGEgaW5ub3ZhY2nDs24gdGVjbm9sw7NnaWNhLiBVbmEgZmFjZXRhIGNydWNpYWwgZGUgZXN0YSBpbmR1c3RyaWEgZXMgZWwgbWVyY2FkbyBkZSBhdXRvcGFydGVzLCBxdWUgc2UgZXJpZ2UgY29tbyB1biBwaWxhciBmdW5kYW1lbnRhbCBwYXJhIGxhIG9wZXJhdGl2aWRhZCB5IGVsIGRlc2Fycm9sbG8gZGUgbGEgaW5kdXN0cmlhIGF1dG9tb3RyaXogZW4gc3UgY29uanVudG8uIEVzdGUgc2VnbWVudG8gaW5jbHV5ZSBkZXNkZSBsYSBmYWJyaWNhY2nDs24gZGUgY29tcG9uZW50ZXMgZXNlbmNpYWxlcyBkZWwgdmVow61jdWxvIGhhc3RhIHNpc3RlbWFzIGF2YW56YWRvcyBxdWUgbWVqb3JhbiBsYSBzZWd1cmlkYWQsIGVsIHJlbmRpbWllbnRvIHkgbGEgY29tb2RpZGFkLgoKTGEgaW50ZXJhY2Npw7NuIGVudHJlIGxvcyBmYWJyaWNhbnRlcyBkZSBhdXRvbcOzdmlsZXMgeSBsb3MgcHJvdmVlZG9yZXMgZGUgYXV0b3BhcnRlcyBlcyBpbnRyw61uc2VjYSBhbCBjaWNsbyBkZSB2aWRhIGRlbCBwcm9kdWN0byBhdXRvbW90cml6LCBhZmVjdGFuZG8gZGlyZWN0YW1lbnRlIGxhIGNhZGVuYSBkZSBzdW1pbmlzdHJvLCBsYSBpbm5vdmFjacOzbiBlbiBlbCBkaXNlw7FvIGRlIHByb2R1Y3RvcyB5LCBlbiDDumx0aW1hIGluc3RhbmNpYSwgbGEgY29tcGV0aXRpdmlkYWQgZW4gZWwgbWVyY2FkbyBnbG9iYWwuIEFkZW3DoXMsIGVsIG1lcmNhZG8gZGUgYXV0b3BhcnRlcyBlbiBNw6l4aWNvIHNlIHZlIGluZmx1ZW5jaWFkbyBwb3IgZmFjdG9yZXMgY29tbyBsYXMgcmVndWxhY2lvbmVzIGd1YmVybmFtZW50YWxlcywgbG9zIHRyYXRhZG9zIGRlIGxpYnJlIGNvbWVyY2lvLCBsYXMgdGVuZGVuY2lhcyBkZSBjb25zdW1vIHkgbG9zIGF2YW5jZXMgdGVjbm9sw7NnaWNvcywgbG8gcXVlIGxvIGNvbnZpZXJ0ZSBlbiB1biBjYW1wbyBkZSBlc3R1ZGlvIGRpbsOhbWljbyB5IGNvbXBsZWpvLgoKIyMjIyBFeHBsb3JhY2nDs24gZGUgRXhwb3J0YWNpw7NuIGRlIFZlaMOtY3Vsb3MKClBhcmEgcHJvZnVuZGl6YXIgZW4gZWwgZW50ZW5kaW1pZW50byBkZSBlc3RhIGluZHVzdHJpYSwgc2UgcmVhbGl6YXLDoSB1biBhbsOhbGlzaXMgZXhoYXVzdGl2byB1dGlsaXphbmRvIGRpdmVyc2FzIGJhc2VzIGRlIGRhdG9zIHJlY29waWxhZGFzIGRlIG3Dumx0aXBsZXMgZnVlbnRlcy4gRXN0ZSBhbsOhbGlzaXMgYnVzY2Fyw6EgaWRlbnRpZmljYXIgdGVuZGVuY2lhcywgZGVzYWbDrW9zIHkgb3BvcnR1bmlkYWRlcyBkZW50cm8gZGVsIG1lcmNhZG8gZGUgYXV0b3BhcnRlcywgYXPDrSBjb21vIHN1IGludGVyY29uZXhpw7NuIGNvbiBsYSBpbmR1c3RyaWEgYXV0b21vdHJpeiBlbiBnZW5lcmFsLiBTZSBleGFtaW5hcsOhbiBhc3BlY3RvcyBjb21vIGxhIGV2b2x1Y2nDs24gZGUgbGEgZGVtYW5kYSBkZSBhdXRvcGFydGVzLCBsYSBjYWRlbmEgZGUgdmFsb3IsIGVsIGltcGFjdG8gZGUgbGEgdGVjbm9sb2fDrWEgZW4gbGEgcHJvZHVjY2nDs24geSBlbCBkaXNlw7FvIGRlIGF1dG9wYXJ0ZXMsIGFzw60gY29tbyBsYXMgZXN0cmF0ZWdpYXMgYWRvcHRhZGFzIHBvciBsYXMgZW1wcmVzYXMgcGFyYSBuYXZlZ2FyIGVuIHVuIGVudG9ybm8gZWNvbsOzbWljbyB5IHJlZ3VsYXRvcmlvIGVuIGNvbnN0YW50ZSBjYW1iaW8uCgoqKkFuYWxpc2lzIGRlIEV4cG9ydGFjacOzbiBkZSBWZWhpY3Vsb3MqKgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpteF92ZWhpY2xlX2V4cG9ydHMgPC0gcmVhZF9leGNlbCgiL1VzZXJzL2RhdmlkZHJ1bXMxODAvVGVjL0Nhc2VfU3R1ZHlfRm9ybS9kYXRhYmFzZXMvaW5kdXN0cnlfYXV0b3NfbXgvZXhwb3J0YWNpb25fdmVoaWN1bG9zLnhsc3giKQoKbXhfdmVoaWNsZV9leHBvcnRzX3N1bW1hcnkgPC0gbXhfdmVoaWNsZV9leHBvcnRzICU+JQogIGdyb3VwX2J5KEHDsW8sIFNlZ21lbnRvKSAlPiUKICBzdW1tYXJpc2UoQ2FudGlkYWRfVG90YWwgPSBzdW0oQ2FudGlkYWQsIG5hLnJtID0gVFJVRSkpCgojIERlZmluaXIgbGEgcGFsZXRhIGRlIGNvbG9yZXMgcGVyc29uYWxpemFkYQpjb2xvcmVzIDwtIGMoIiMyRDMyNTAiLCAiIzQzNTU4NSIsICIjNzA3N0ExIiwgIiNGNkIxN0EiLCAiIzlFQzhCOSIsICIjQkUzMTQ0IikKCiMgQXNlZ3VyYXJzZSBkZSBxdWUgaGF5IHN1ZmljaWVudGVzIGNvbG9yZXMgcGFyYSBsb3Mgc2VnbWVudG9zCiMgUmVwZXRpciBsYSBwYWxldGEgc2kgaGF5IG3DoXMgc2VnbWVudG9zIHF1ZSBjb2xvcmVzCm5fc2VnbWVudG9zIDwtIGxlbmd0aCh1bmlxdWUobXhfdmVoaWNsZV9leHBvcnRzX3N1bW1hcnkkU2VnbWVudG8pKQppZiAobl9zZWdtZW50b3MgPiBsZW5ndGgoY29sb3JlcykpIHsKICBjb2xvcmVzIDwtIHJlcChjb2xvcmVzLCBsZW5ndGgub3V0ID0gbl9zZWdtZW50b3MpCn0KCiMgR3LDoWZpY28gZGUgbMOtbmVhcyBjb24gbGEgcGFsZXRhIGRlIGNvbG9yZXMgcGVyc29uYWxpemFkYQpnZ3Bsb3QobXhfdmVoaWNsZV9leHBvcnRzX3N1bW1hcnksIGFlcyh4ID0gQcOxbywgeSA9IENhbnRpZGFkX1RvdGFsLCBjb2xvciA9IFNlZ21lbnRvLCBncm91cCA9IFNlZ21lbnRvKSkgKyAKICBnZW9tX2xpbmUoKSArICMgRGlidWphIGzDrW5lYXMKICBnZW9tX3BvaW50KCkgKyAjIEHDsWFkZSBwdW50b3MgZW4gY2FkYSBkYXRvCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yZXMpICsgIyBVc2EgbGEgcGFsZXRhIGRlIGNvbG9yZXMgZGVmaW5pZGEKICB0aGVtZV9taW5pbWFsKCkgKyAjIFVzYSB1biB0ZW1hIG1pbmltYWxpc3RhCiAgbGFicyh0aXRsZSA9ICJFdm9sdWNpw7NuIGRlIGxhIEV4cG9ydGFjacOzbiBkZSBTZWdtZW50byBkZSBWZWjDrWN1bG8gYSBsbyBMYXJnbyBkZSBsb3MgQcOxb3MiLAogICAgICAgeCA9ICJBw7FvIiwKICAgICAgIHkgPSAiQ2FudGlkYWQgVG90YWwiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKYGBgCgoqKjEuIENyZWNpbWllbnRvIGRlIFNVVnM6KioKICAgICAtIExhIGV4cG9ydGFjacOzbiBkZSBTVVZzIGhhIHZpc3RvIHVuIGNyZWNpbWllbnRvIHNpZ25pZmljYXRpdm8gaGFzdGEgMjAxOCwgc2VndWlkbyBkZSB1bmEgZGlzbWludWNpw7NuLiBFc3RvIHBvZHLDrWEgaW5kaWNhciBjYW1iaW9zIGVuIGxhIHByZWZlcmVuY2lhIGRlbCBjb25zdW1pZG9yIG8gZW4gbGEgZGluw6FtaWNhIGRlbCBtZXJjYWRvLiBGT1JNIHB1ZWRlIGFwcm92ZWNoYXIgZXN0YSB0ZW5kZW5jaWEgb2ZyZWNpZW5kbyBzb2x1Y2lvbmVzIGRlIGVtcGFxdWUgcGVyc29uYWxpemFkYXMgcGFyYSBlc3RlIHNlZ21lbnRvLCBxdWUgcGFyZWNlIHRlbmVyIHVuYSBhbHRhIHZhcmlhYmlsaWRhZCBlbiBsYSBkZW1hbmRhLgoKKioyLiBWb2xhdGlsaWRhZCBlbiBTZWdtZW50byBkZSBMdWpvOioqCiAgICAgLSBFbCBzZWdtZW50byBkZSBsdWpvIG11ZXN0cmEgdm9sYXRpbGlkYWQgY29uIHVuIHBpY28gbWFyY2FkbyBhbHJlZGVkb3IgZGUgMjAxOC4gRXN0byBwdWVkZSBhYnJpciBvcG9ydHVuaWRhZGVzIHBhcmEgRk9STSBlbiB0w6lybWlub3MgZGUgcHJvcG9yY2lvbmFyIGVtcGFxdWVzIGRlIGFsdGEgY2FsaWRhZCBxdWUgY29pbmNpZGFuIGNvbiBsYXMgZXhwZWN0YXRpdmFzIGRlIGxvcyBmYWJyaWNhbnRlcyBkZSB2ZWjDrWN1bG9zIGRlIGx1am8geSBzdXMgY29uc3VtaWRvcmVzLgoKKiozLiBDYcOtZGEgR2VuZXJhbCBQb3N0LTIwMTg6KioKICAgICAtIERlc3B1w6lzIGRlIDIwMTgsIHRvZG9zIGxvcyBzZWdtZW50b3MgZXhjZXB0byBsb3Mgc3ViY29tcGFjdG9zIG11ZXN0cmFuIHVuYSBjYcOtZGEsIGxvIHF1ZSBwb2Ryw61hIGRlYmVyc2UgYSBmYWN0b3JlcyBlY29uw7NtaWNvcyBnbG9iYWxlcywgcG9sw610aWNhcyBjb21lcmNpYWxlcyBvIGxhIHBhbmRlbWlhLiBGT1JNIGRlYmUgZXN0YXIgYXRlbnRvIGEgZXN0b3MgZmFjdG9yZXMgZXh0ZXJub3MgcXVlIGFmZWN0YW4gbGEgZGVtYW5kYSBkZSBzdXMgcHJvZHVjdG9zLgoKKio0LiBCZW5lZmljaW9zIFBvdGVuY2lhbGVzIHBhcmEgRk9STToqKgogICAgIC0gRWwgYW7DoWxpc2lzIGRlIGVzdGFzIHRlbmRlbmNpYXMgZXMgdml0YWwgcGFyYSBGT1JNLCB5YSBxdWUgcHJvcG9yY2lvbmEgaW5mb3JtYWNpw7NuIHNvYnJlIHF1w6kgc2VnbWVudG9zIHBvZHLDrWFuIHJlcXVlcmlyIG3DoXMgZW1wYXF1ZXMgZW4gZWwgZnV0dXJvLiBFc3RvIHB1ZWRlIGd1aWFyIHN1cyBkZWNpc2lvbmVzIGRlIGludmVyc2nDs24geSBlc3RyYXRlZ2lhcyBkZSBwcm9kdWNjacOzbiBwYXJhIGxvcyBwcsOzeGltb3MgYcOxb3MuCgoqKjUuIE1vZGVsbyBQcmVkaWN0aXZvIHBhcmEgbGEgRGVtYW5kYToqKgogICAgIC0gVXRpbGl6YXIgZXN0b3MgZGF0b3MgcGFyYSBkZXNhcnJvbGxhciB1biBtb2RlbG8gcHJlZGljdGl2byBwb2Ryw61hIGF5dWRhciBhIEZPUk0gYSBhbnRpY2lwYXJzZSBhIGxhcyBuZWNlc2lkYWRlcyBkZWwgbWVyY2Fkby4gSGVycmFtaWVudGFzIGRlIGFuw6FsaXNpcyBwcmVkaWN0aXZvLCBjb21vIGVsIE1hY2hpbmUgTGVhcm5pbmcsIHBvZHLDrWFuIHVzYXJzZSBwYXJhIHByZXZlciBsYSBkZW1hbmRhIGZ1dHVyYSBiYXPDoW5kb3NlIGVuIGxhcyB0ZW5kZW5jaWFzIGhpc3TDs3JpY2FzIHkgZmFjdG9yZXMgZXh0ZXJub3MuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFN1bWFyaXphciBsYSBjYW50aWRhZCB0b3RhbCBwb3IgUGHDrXMgZGVzdGlubyB5IG9idGVuZXIgbG9zIHRvcCA1CnRvcF9wYWlzZXNfZGVzdGlubyA8LSBteF92ZWhpY2xlX2V4cG9ydHMgJT4lCiAgZ3JvdXBfYnkoYFBhw61zIGRlc3Rpbm9gKSAlPiUKICBzdW1tYXJpc2UoQ2FudGlkYWRfVG90YWwgPSBzdW0oQ2FudGlkYWQsIG5hLnJtID0gVFJVRSkpICU+JQogIGFycmFuZ2UoZGVzYyhDYW50aWRhZF9Ub3RhbCkpICU+JQogIHNsaWNlX2hlYWQobiA9IDUpCgojIEZpbHRyYXIgZWwgZGF0YWZyYW1lIG9yaWdpbmFsIHBhcmEgdGVuZXIgc29sbyBsb3MgdG9wIDUgUGHDrXMgZGVzdGlubwpteF92ZWhpY2xlX2V4cG9ydHNfdG9wNSA8LSBteF92ZWhpY2xlX2V4cG9ydHMgJT4lCiAgZmlsdGVyKGBQYcOtcyBkZXN0aW5vYCAlaW4lIHRvcF9wYWlzZXNfZGVzdGlubyRgUGHDrXMgZGVzdGlub2ApCgojIEPDs2RpZ28gcGFyYSB1biBib3ggcGxvdCBkZSBsYSB2YXJpYWJsZSBDYW50aWRhZCBwb3IgbG9zIHRvcCA1IFBhw61zIGRlc3Rpbm8KZ2dwbG90KG14X3ZlaGljbGVfZXhwb3J0c190b3A1LCBhZXMoeCA9IGBQYcOtcyBkZXN0aW5vYCwgeSA9IENhbnRpZGFkKSkgKyAKICBnZW9tX2JveHBsb3QoKSArICAKICB0aGVtZV9taW5pbWFsKCkgKyAKICBsYWJzKHRpdGxlID0gIkJveCBQbG90IGRlIENhbnRpZGFkIHBvciBUb3AgNSBQYcOtcyBEZXN0aW5vIiwKICAgICAgIHggPSAiUGHDrXMgRGVzdGlubyIsCiAgICAgICB5ID0gIkNhbnRpZGFkIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCmBgYAoqKjEuIERvbWluYW5jaWEgZGUgRXN0YWRvcyBVbmlkb3M6KioKICAgICAtIEVzdGFkb3MgVW5pZG9zIG11ZXN0cmEgdW5hIG1lZGlhbmEgeSB1biByYW5nbyBpbnRlcmN1YXJ0w61saWNvIHN1cGVyaW9yIGEgb3Ryb3MgZGVzdGlub3MsIGxvIGN1YWwgaW5kaWNhIHF1ZSBlcyBlbCBwcmluY2lwYWwgbWVyY2FkbyBwYXJhIGxhIGV4cG9ydGFjacOzbi4gRk9STSBwdWVkZSBjZW50cmFyc2UgZW4gYXVtZW50YXIgbGEgY2FwYWNpZGFkIGRlIHByb2R1Y2Npw7NuIHkgbWVqb3JhciBsYXMgc29sdWNpb25lcyBsb2fDrXN0aWNhcyBwYXJhIHNhdGlzZmFjZXIgbGEgYWx0YSBkZW1hbmRhIGRlIGVtcGFxdWVzIGVuIGVzdGUgbWVyY2Fkby4KCioqMi4gVmFyaWFiaWxpZGFkIGVuICdObyBFc3BlY2lmaWNhZG8nOioqCiAgICAgLSBMYSBjYXRlZ29yw61hICdObyBFc3BlY2lmaWNhZG8nIHRpZW5lIHVuYSBhbHRhIHZhcmlhYmlsaWRhZCB5IHZhbG9yZXMgYXTDrXBpY29zLCBsbyBxdWUgcG9kcsOtYSBpbmRpY2FyIG9wb3J0dW5pZGFkZXMgbm8gZXhwbG9yYWRhcyBvIGRhdG9zIGluY29tcGxldG9zLiBGT1JNIHBvZHLDrWEgaW52ZXN0aWdhciBlc3RvcyBjYXNvcyBwYXJhIGlkZW50aWZpY2FyIHBvc2libGVzIG51ZXZvcyBtZXJjYWRvcyBvIG1lam9yYXIgbGEgcHJlY2lzacOzbiBlbiBsYSByZWNvcGlsYWNpw7NuIGRlIGRhdG9zLgoKKiozLiBDb25zaXN0ZW5jaWEgZW4gQWxlbWFuaWEgeSBCcmFzaWw6KioKICAgICAtIEFsZW1hbmlhIHkgQnJhc2lsIG11ZXN0cmFuIHVuYSBtZW5vciBkaXNwZXJzacOzbiB5IGNvbnNpc3RlbmNpYSBlbiBsb3MgZW52w61vcywgbG8gcXVlIHBvZHLDrWEgcmVmbGVqYXIgbWVyY2Fkb3MgZXN0YWJsZWNpZG9zIGNvbiBkZW1hbmRhcyBwcmVkZWNpYmxlcy4gRk9STSBwdWVkZSB1dGlsaXphciBlc3RhIGluZm9ybWFjacOzbiBwYXJhIG9wdGltaXphciBpbnZlbnRhcmlvcyB5IHByZXZlciByZWN1cnNvcyBkZSBwcm9kdWNjacOzbi4KCioqNC4gQmVuZWZpY2lvcyBkZWwgQW7DoWxpc2lzIHBhcmEgRk9STToqKgogICAgIC0gQW5hbGl6YXIgZXN0YSBkaXN0cmlidWNpw7NuIGRlIGV4cG9ydGFjaW9uZXMgcG9kcsOtYSBheXVkYXIgYSBGT1JNIGEgZW50ZW5kZXIgbWVqb3IgbGEgdmFyaWFiaWxpZGFkIHkgbGEgY29uc2lzdGVuY2lhIGVuIGxhIGRlbWFuZGEgZW50cmUgZGlmZXJlbnRlcyBtZXJjYWRvcy4gRXN0YSBpbmZvcm1hY2nDs24gcHVlZGUgc2VyIGNyw610aWNhIHBhcmEgb3B0aW1pemFyIGxhIGNhZGVuYSBkZSBzdW1pbmlzdHJvIHkgcG9kZXIgZGVzYXJyb2xsYXIgdW4gbW9kZWxvIHF1ZSBheXVkZSBhIHByZWRlY2lyIHkgY29udHJvbGFyIGxvcyBuaXZlbGVzIGRlIGludmVudGFyaW8gbmVjZXNhcmlvcy4KCioqNS4gTW9kZWxvIFByZWRpY3Rpdm8gcGFyYSBsYSBEZW1hbmRhOioqCiAgICAgLSBEZXNhcnJvbGxhciB1biBtb2RlbG8gcHJlZGljdGl2byBiYXNhZG8gZW4gZXN0b3MgZGF0b3MgcGVybWl0aXLDrWEgYSBGT1JNIGFudGljaXBhciBsYSBkZW1hbmRhIHkgYWp1c3RhciBsYSBwcm9kdWNjacOzbiBkZSBmb3JtYSBwcm9hY3RpdmEuIExhIHV0aWxpemFjacOzbiBkZSB0w6ljbmljYXMgZXN0YWTDrXN0aWNhcyBjb21vIGxhIHJlZ3Jlc2nDs24sIGNvbmp1bnRhbWVudGUgY29uIGFsZ29yaXRtb3MgZGUgbWFjaGluZSBsZWFybmluZywgcG9kcsOtYSBwcm9wb3JjaW9uYXIgZXN0aW1hY2lvbmVzIHByZWNpc2FzIGRlIGxhIGRlbWFuZGEgZnV0dXJhIGJhc8OhbmRvc2UgZW4gcGF0cm9uZXMgaGlzdMOzcmljb3MgeSB0ZW5kZW5jaWFzIGFjdHVhbGVzLgoKCiMjIyMgRXhwbG9yYWNpw7NuIGEgTWVyY2FkbyBkZSBBdXRvcGFydGVzCgpBIHRyYXbDqXMgZGUgZXN0ZSBlbmZvcXVlIGFuYWzDrXRpY28sIHNlIGVzcGVyYSBvYnRlbmVyIGluc2lnaHRzIHZhbGlvc29zIHF1ZSBjb250cmlidXlhbiBhIHVuYSBtZWpvciBjb21wcmVuc2nDs24gZGVsIG1lcmNhZG8gZGUgYXV0b3BhcnRlcyBlbiBNw6l4aWNvIHkgc3Ugcm9sIGNyw610aWNvIGRlbnRybyBkZSBsYSBpbmR1c3RyaWEgYXV0b21vdHJpei4gRXN0b3MgaGFsbGF6Z29zIHBvZHLDrWFuIG9mcmVjZXIgZGlyZWN0cmljZXMgcGFyYSBsYSB0b21hIGRlIGRlY2lzaW9uZXMgZXN0cmF0w6lnaWNhcyBwb3IgcGFydGUgZGUgbG9zIGFjdG9yZXMgZGUgbGEgaW5kdXN0cmlhLCBhc8OtIGNvbW8gcGFyYSBlbCBkaXNlw7FvIGRlIHBvbMOtdGljYXMgcMO6YmxpY2FzIHF1ZSBwcm9tdWV2YW4gZWwgY3JlY2ltaWVudG8geSBsYSBzb3N0ZW5pYmlsaWRhZCBkZWwgc2VjdG9yLiBMYSBtZXRvZG9sb2fDrWEgeSBsb3MgcmVzdWx0YWRvcyBkZSBlc3RlIGFuw6FsaXNpcyBlc3RhcsOhbiBmdW5kYW1lbnRhZG9zIGVuIGxhIGluZm9ybWFjacOzbiBkZXRhbGxhZGEgcHJvcG9yY2lvbmFkYSBlbiBsYXMgYmFzZXMgZGUgZGF0b3MsIGN1eWFzIGZ1ZW50ZXMgc2UgZW5jdWVudHJhbiBtZXRpY3Vsb3NhbWVudGUgZG9jdW1lbnRhZGFzIGVuIGVsIFJFQURNRSBhZGp1bnRvIGEgbGFzIGJhc2VzIGRlIGRhdG9zLCBhc2VndXJhbmRvIGFzw60gbGEgdHJhbnNwYXJlbmNpYSB5IGxhIGZpYWJpbGlkYWQgZGUgbGEgaW52ZXN0aWdhY2nDs24gcmVhbGl6YWRhLgoKKipJbXBvcnRhY2nDs25lcywgRXhwb3J0YWNpw7NuZXMgeSBQcm9kdWNjacOzbiBkZSBBdXRvcGFydGVzKioKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbXhfYXV0b3BhcnRzX21hcmtldCA8LSByZWFkX2NzdigiL1VzZXJzL2RhdmlkZHJ1bXMxODAvVGVjL0Nhc2VfU3R1ZHlfRm9ybS9kYXRhYmFzZXMvaW5kdXN0cnlfYXV0b3NfbXgvbXhfYXV0b3BhcnRzX21hcmtldC5jc3YiKQoKIyBDb2xvcmVzCmNvbG9ycyA8LSBjKCJQcm9kdWNjacOzbiBsb2NhbCB0b3RhbCIgPSAiIzAwQkZDNCIsCiAgICAgICAgICAgICJFeHBvcnRhY2lvbmVzIHRvdGFsZXMiID0gIiNGODc2NkQiLAogICAgICAgICAgICAiSW1wb3J0YWNpb25lcyB0b3RhbGVzIiA9ICIjN0NBRTAwIiwKICAgICAgICAgICAgIkltcG9ydGFjaW9uZXMgZGUgRUUuVVUuIiA9ICIjQzc3Q0ZGIikKCgojIFVzYXIgZ2dwbG90MiBwYXJhIGdyYWZpY2FyIGRpcmVjdGFtZW50ZSBsb3MgZGF0b3MKZ2dwbG90KGRhdGEgPSBteF9hdXRvcGFydHNfbWFya2V0KSArCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IHRvdGFsX2xvY2FsX3Byb2R1Y3Rpb24sIGdyb3VwID0gMSwgY29sb3VyID0gIlByb2R1Y2Npw7NuIGxvY2FsIHRvdGFsIiksIHNpemUgPSAxKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IHRvdGFsX2V4cG9ydHMsIGdyb3VwID0gMSwgY29sb3VyID0gIkV4cG9ydGFjaW9uZXMgdG90YWxlcyIpLCBzaXplID0gMSkgKwogIGdlb21fbGluZShhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9pbXBvcnRzLCBncm91cCA9IDEsIGNvbG91ciA9ICJJbXBvcnRhY2lvbmVzIHRvdGFsZXMiKSwgc2l6ZSA9IDEpICsKICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gaW1wb3J0c19mcm9tX1VTLCBncm91cCA9IDEsIGNvbG91ciA9ICJJbXBvcnRhY2lvbmVzIGRlIEVFLlVVLiIpLCBzaXplID0gMSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSB5ZWFyLCB5ID0gdG90YWxfbG9jYWxfcHJvZHVjdGlvbiwgY29sb3VyID0gIlByb2R1Y2Npw7NuIGxvY2FsIHRvdGFsIiksIHNpemUgPSAzKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9leHBvcnRzLCBjb2xvdXIgPSAiRXhwb3J0YWNpb25lcyB0b3RhbGVzIiksIHNpemUgPSAzKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9pbXBvcnRzLCBjb2xvdXIgPSAiSW1wb3J0YWNpb25lcyB0b3RhbGVzIiksIHNpemUgPSAzKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHllYXIsIHkgPSBpbXBvcnRzX2Zyb21fVVMsIGNvbG91ciA9ICJJbXBvcnRhY2lvbmVzIGRlIEVFLlVVLiIpLCBzaXplID0gMykgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sb3JzKSArCiAgbGFicyh0aXRsZSA9ICJNZXJjYWRvIGRlIEF1dG9wYXJ0ZXMgZW4gTcOpeGljbyAoMjAxOC0yMDIyKSIsCiAgICAgICB4ID0gIkHDsW8iLAogICAgICAgeSA9ICJWYWxvciAoZW4gbWlsZXMgZGUgbWlsbG9uZXMgZGUgVVNEKSIsCiAgICAgICBjb2xvdXIgPSAiVmFyaWFibGUiKSArCiAgdGhlbWVfbWluaW1hbCgpIAoKYGBgCgoqKjEuIFByb2R1Y2Npw7NuIExvY2FsIFRvdGFsOioqCiAgICAgLSBMYSBsw61uZWEgcXVlIHJlcHJlc2VudGEgbGEgcHJvZHVjY2nDs24gbG9jYWwgdG90YWwgbXVlc3RyYSB1bmEgdGVuZGVuY2lhIGRlY3JlY2llbnRlIGRlIDIwMTggYSAyMDE5LgogICAgIC0gSGF5IHVuYSBsZXZlIHJlY3VwZXJhY2nDs24gZW4gMjAyMCwgc2VndWlkYSBkZSB1bmEgY2HDrWRhIGVuIDIwMjEsIHkgdW4gbGlnZXJvIGF1bWVudG8gZW4gMjAyMi4KICAgICAtIEVzdGEgdGVuZGVuY2lhIHB1ZWRlIGluZGljYXIgZGVzYWbDrW9zIGVuIGVsIHNlY3RvciBkZSBsYSBwcm9kdWNjacOzbiBvIGNhbWJpb3MgZW4gbGEgZGVtYW5kYSBpbnRlcm5hLgoKKioyLiBFeHBvcnRhY2lvbmVzIFRvdGFsZXM6KioKICAgICAtIExhcyBleHBvcnRhY2lvbmVzIG11ZXN0cmFuIHVuYSByZWR1Y2Npw7NuIHNpZ25pZmljYXRpdmEgZW4gMjAyMCwgcG9zaWJsZW1lbnRlIGRlYmlkbyBhbCBpbXBhY3RvIGRlIGxhIHBhbmRlbWlhIGRlIENPVklELTE5IGVuIGVsIGNvbWVyY2lvIGdsb2JhbC4KICAgICAtIFNlIG9ic2VydmEgdW5hIHJlY3VwZXJhY2nDs24gZnVlcnRlIGVuIDIwMjEgeSAyMDIyLCBpbmRpY2FuZG8gdW5hIHBvc2libGUgcmVzaWxpZW5jaWEgbyBhZGFwdGFjacOzbiBkZWwgbWVyY2FkbyBkZSBleHBvcnRhY2nDs24uCgoqKjMuIEltcG9ydGFjaW9uZXMgVG90YWxlczoqKgogICAgIC0gTGFzIGltcG9ydGFjaW9uZXMgcHJlc2VudGFuIHVuIGluY3JlbWVudG8gY29uc3RhbnRlIGEgbG8gbGFyZ28gZGUgbG9zIGHDsW9zLCBjb24gdW5hIHBlcXVlw7FhIGRpc21pbnVjacOzbiBlbiAyMDIxLgogICAgIC0gTGEgdGVuZGVuY2lhIGFzY2VuZGVudGUgcG9kcsOtYSByZWZsZWphciB1bmEgY3JlY2llbnRlIGRlcGVuZGVuY2lhIGRlIGNvbXBvbmVudGVzIGV4dGVybm9zIG8gdW4gYXVtZW50byBlbiBsYSBkZW1hbmRhIGRlIGF1dG9wYXJ0ZXMgbm8gcHJvZHVjaWRhcyBsb2NhbG1lbnRlLgoKKio0LiBJbXBvcnRhY2lvbmVzIGRlIEVFLlVVLjoqKgogICAgIC0gTGFzIGltcG9ydGFjaW9uZXMgZGVzZGUgRUUuVVUuIGhhbiBkaXNtaW51aWRvIHNpZ25pZmljYXRpdmFtZW50ZSBkZXNkZSAyMDE4IGhhc3RhIDIwMjAuCiAgICAgLSBIYXkgdW4gYXVtZW50byBub3RhYmxlIGVuIDIwMjEsIHF1ZSBzZSByZXZpZXJ0ZSBlbiAyMDIyLCBzdWdpcmllbmRvIGZsdWN0dWFjaW9uZXMgZW4gbGFzIGRpbsOhbWljYXMgY29tZXJjaWFsZXMgY29uIEVFLlVVLgoKCioqTWVyY2FkbyBkZSBBdXRvcGFydGVzIE14KioKYGBge3J9Cm14X2F1dG9wYXJ0c19tYXJrZXQgPC0gbmEub21pdChteF9hdXRvcGFydHNfbWFya2V0KQoKdHVycXVvaXNlX3BhbGV0dGUgPC0gYygiIzhhZTBkYiIsICIjNWRjMWI5IiwgIiM0MmE4YTEiLCAiIzIzOTA4OSIpCgojIENyZWFyIGxhIGdyw6FmaWNhIGRlIGJhcnJhcyBjb24gZXNjYWxhIGRlIGNvbG9yIHBlcnNvbmFsaXphZGEKZ2dwbG90KG14X2F1dG9wYXJ0c19tYXJrZXQsIGFlcyh4ID0gZmFjdG9yKHllYXIpLCB5ID0gdG90YWxfbWFya2V0X3NpemUsIGZpbGwgPSB0b3RhbF9tYXJrZXRfc2l6ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IHR1cnF1b2lzZV9wYWxldHRlKSArCiAgbGFicyh4ID0gIkHDsW8iLCB5ID0gIlRhbWHDsW8gVG90YWwgZGVsIE1lcmNhZG8gKGVuIG1pbGVzIGRlIG1pbGxvbmVzIGRlIFVTRCkiLAogICAgICAgdGl0bGUgPSAiVGFtYcOxbyBUb3RhbCBkZWwgTWVyY2FkbyBkZSBBdXRvcGFydGVzIGVuIE3DqXhpY28gKDIwMTgtMjAyMikiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAKCioqMS4gSW1wYWN0byBkZSBsYSBQYW5kZW1pYSBlbiAyMDIwOioqCiAgICAgLSBMYSBtYXJjYWRhIGNhw61kYSBlbiAyMDIwIHB1ZWRlIGNvcnJlbGFjaW9uYXJzZSBjb24gbGEgcGFuZGVtaWEgZGUgQ09WSUQtMTksIHF1ZSBhZmVjdMOzIGdsb2JhbG1lbnRlIGxhIHByb2R1Y2Npw7NuIHkgdmVudGEgZGUgYXV0b23Ds3ZpbGVzLiBQYXJhIHVuYSBlbXByZXNhIGNvbW8gRk9STSwgZXNwZWNpYWxpemFkYSBlbiBlbXBhcXVlcyBwYXJhIGF1dG9wYXJ0ZXMsIGVzdG8gcG9kcsOtYSBoYWJlciByZXByZXNlbnRhZG8gdW4gcmV0byBzaWduaWZpY2F0aXZvLCBwb3NpYmxlbWVudGUgbGxldmFuZG8gYSB1bmEgcmVkdWNjacOzbiBlbiBsYSBkZW1hbmRhIGRlIHN1cyBwcm9kdWN0b3MgZGUgZW1wYXF1ZXRhZG8uCgoqKjIuIFJlY3VwZXJhY2nDs24gUG9zdC1QYW5kZW1pYToqKgogICAgIC0gRWwgcmVib3RlIGVuIDIwMjEgc3VnaWVyZSB1bmEgcmVjdXBlcmFjacOzbiBwb3N0LXBhbmRlbWlhIHF1ZSBoYWJyw61hIHBvZGlkbyBnZW5lcmFyIHVuIGF1bWVudG8gZW4gbGEgZGVtYW5kYSBkZSB2ZWjDrWN1bG9zIHksIGNvbnNlY3VlbnRlbWVudGUsIGRlIGF1dG9wYXJ0ZXMuIEVzdG8gcHVlZGUgaGFiZXIgc2lkbyB1bmEgb3BvcnR1bmlkYWQgcGFyYSBGT1JNIGRlIGV4cGFuZGlyIG8gZGl2ZXJzaWZpY2FyIHN1IGzDrW5lYSBkZSBwcm9kdWN0b3MgZGUgZW1wYXF1ZSwgYXByb3ZlY2hhbmRvIGxhIHJlYWN0aXZhY2nDs24gZGVsIG1lcmNhZG8uCgoqKjMuIElubm92YWNpw7NuIGNvbW8gRmFjdG9yIGRlIENyZWNpbWllbnRvOioqCiAgICAgLSBMYSBpbm5vdmFjacOzbiBkZSBwcm9kdWN0b3MgZGUgZW1wYXF1ZSBxdWUgcGVybWl0ZW4gYWhvcnJvcyBzaWduaWZpY2F0aXZvcyBlbiBlc3BhY2lvIHkgY29zdG9zIGRlIGxvZ8Otc3RpY2EgcG9yIHBhcnRlIGRlIEZPUk0gcG9kcsOtYSBoYWJlciBzaWRvIHVuIGZhY3RvciBkZXRlcm1pbmFudGUgZW4gc3UgcG90ZW5jaWFsIGRlIGNyZWNpbWllbnRvIGR1cmFudGUgZWwgcGVyaW9kbyBkZSByZWN1cGVyYWNpw7NuIGVjb27Ds21pY2EsIGVzcGVjaWFsbWVudGUgY29uc2lkZXJhbmRvIGxhIHRlbmRlbmNpYSBjcmVjaWVudGUgaGFjaWEgbGEgZWZpY2llbmNpYSB5IHNvc3RlbmliaWxpZGFkIGVuIGxhIGluZHVzdHJpYSBhdXRvbW90cml6LgoKKio0LiBQb3RlbmNpYWwgcGFyYSBlbCBGdXR1cm86KioKICAgICAtIERhZGEgbGEgdGVuZGVuY2lhIGRlIHJlY3VwZXJhY2nDs24gZGVsIG1lcmNhZG8gZW4gMjAyMiwgZW1wcmVzYXMgY29tbyBGT1JNIGVzdMOhbiBiaWVuIHBvc2ljaW9uYWRhcyBwYXJhIGNhcGl0YWxpemFyIGVsIGNyZWNpbWllbnRvIGNvbnRpbnVvIGRlIGxhIGluZHVzdHJpYSBhdXRvbW90cml6LiBMYSBhZGFwdGFjacOzbiBhIGxhcyBudWV2YXMgbm9ybWF0aXZhcyBhbWJpZW50YWxlcyB5IGxhIG1lam9yYSBlbiBsYSBlZmljaWVuY2lhIGRlIGxhIGNhZGVuYSBkZSBzdW1pbmlzdHJvIHNlcsOhbiBjbGF2ZXMgcGFyYSBzdSDDqXhpdG8gZnV0dXJvLgoKIyMjIyBJbmR1c3RyaWEgZGVsIGNhcnTDs24KCmBgYHtyfQpjYXJ0b25fZXhwID0gcmVhZC5jc3YoIi9Vc2Vycy9kYXZpZGRydW1zMTgwL1RlYy9DYXNlX1N0dWR5X0Zvcm0vZGF0YWJhc2VzL2luZHVzdHJ5X2NhcnRvbi90ZW1wb3JhcnkvRXhwb3J0ZXJzIG9mIENhcnRvbiBib3hlcyBjYXNlcyBvZiBjb3JydWdhdGVkIHBhcGVyIG9yIGJvYXJkIDIwMjAtMjAyMS5jc3YiKQpjYXJ0b25faW1wID0gcmVhZC5jc3YoIi9Vc2Vycy9kYXZpZGRydW1zMTgwL1RlYy9DYXNlX1N0dWR5X0Zvcm0vZGF0YWJhc2VzL2luZHVzdHJ5X2NhcnRvbi90ZW1wb3JhcnkvSW1wb3J0ZXJzIG9mIENhcnRvbnMgYm94ZXMgY2FzZXMgb2YgY29ycnVnYXRlZCBwYXBlciBvciBib2FyZCAyMDIwLTIwMjEuY3N2IikKZWxlY3RyaWNfMjAxNj1yZWFkLmNzdigiL1VzZXJzL2RhdmlkZHJ1bXMxODAvVGVjL0Nhc2VfU3R1ZHlfRm9ybS9kYXRhYmFzZXMvaW5kdXN0cnlfYXV0b3NfdXNhL3RlbXBvcmFyeS9teF92ZW50YV92ZWhpY3Vsb3NfaGlicmlkb3NfZWxlY3RyaWNvc18yMDE2LmNzdiIpCmVsZWN0cmljXzIwMTc9cmVhZC5jc3YoIi9Vc2Vycy9kYXZpZGRydW1zMTgwL1RlYy9DYXNlX1N0dWR5X0Zvcm0vZGF0YWJhc2VzL2luZHVzdHJ5X2F1dG9zX3VzYS90ZW1wb3JhcnkvbXhfdmVudGFfdmVoaWN1bG9zX2hpYnJpZG9zX2VsZWN0cmljb3NfMjAxNy5jc3YiKQplbGVjdHJpY18yMDE4PXJlYWQuY3N2KCIvVXNlcnMvZGF2aWRkcnVtczE4MC9UZWMvQ2FzZV9TdHVkeV9Gb3JtL2RhdGFiYXNlcy9pbmR1c3RyeV9hdXRvc191c2EvdGVtcG9yYXJ5L214X3ZlbnRhX3ZlaGljdWxvc19oaWJyaWRvc19lbGVjdHJpY29zXzIwMTguY3N2IikKZWxlY3RyaWNfMjAxOT1yZWFkLmNzdigiL1VzZXJzL2RhdmlkZHJ1bXMxODAvVGVjL0Nhc2VfU3R1ZHlfRm9ybS9kYXRhYmFzZXMvaW5kdXN0cnlfYXV0b3NfdXNhL3RlbXBvcmFyeS9teF92ZW50YV92ZWhpY3Vsb3NfaGlicmlkb3NfZWxlY3RyaWNvc18yMDE5LmNzdiIpCmVsZWN0cmljXzIwMjA9cmVhZC5jc3YoIi9Vc2Vycy9kYXZpZGRydW1zMTgwL1RlYy9DYXNlX1N0dWR5X0Zvcm0vZGF0YWJhc2VzL2luZHVzdHJ5X2F1dG9zX3VzYS90ZW1wb3JhcnkvbXhfdmVudGFfdmVoaWN1bG9zX2hpYmlyaWRvc19lbGVjdHJpY29zXzIwMjAuY3N2IikKZWxlY3RyaWNfMjAyMT1yZWFkLmNzdigiL1VzZXJzL2RhdmlkZHJ1bXMxODAvVGVjL0Nhc2VfU3R1ZHlfRm9ybS9kYXRhYmFzZXMvaW5kdXN0cnlfYXV0b3NfdXNhL3RlbXBvcmFyeS9teF92ZW50YV92ZWhpY3Vsb3NfaGlicmlkb3NfZWxlY3RyaWNvc18yMDIxLmNzdiIpCmVsZWN0cmljXzIwMjI9cmVhZC5jc3YoIi9Vc2Vycy9kYXZpZGRydW1zMTgwL1RlYy9DYXNlX1N0dWR5X0Zvcm0vZGF0YWJhc2VzL2luZHVzdHJ5X2F1dG9zX3VzYS90ZW1wb3JhcnkvbXhfdmVudGFfdmVoaWN1bG9zX2hpYnJpZG9zX2VsZWN0cmljb3NfMjAyMi5jc3YiKQplbGVjdHJpY18yMDIzPXJlYWQuY3N2KCIvVXNlcnMvZGF2aWRkcnVtczE4MC9UZWMvQ2FzZV9TdHVkeV9Gb3JtL2RhdGFiYXNlcy9pbmR1c3RyeV9hdXRvc191c2EvdGVtcG9yYXJ5L214X3ZlbnRhX3ZlaGljdWxvc19oaWJyaWRvc19lbGVjdHJpY29zXzIwMjMuY3N2IikKYGBgCgoqRXhwb3J0YWNpb25lcyoKCmBgYHtyfQojIEZpbHRyYXIgbG9zIDE1IHBhw61zZXMgY29uIG1heW9yZXMgdmFsb3JlcyBkZSBjb21lcmNpbyBkZSBleHBvcnRhY2nDs24KdG9wX2NvdW50cmllcyA8LSBjYXJ0b25fZXhwICU+JQogIGdyb3VwX2J5KENvdW50cnkpICU+JQogIHN1bW1hcml6ZShUb3RhbFRyYWRlVmFsdWUgPSBzdW0oVHJhZGUuVmFsdWUpKSAlPiUKICB0b3BfbigxNSwgVG90YWxUcmFkZVZhbHVlKSAlPiUKICBhcnJhbmdlKGRlc2MoVG90YWxUcmFkZVZhbHVlKSkKCiMgVW5pciBsb3MgZGF0b3MgZmlsdHJhZG9zIGNvbiBlbCBkYXRhLmZyYW1lIG9yaWdpbmFsIHBhcmEgb2J0ZW5lciBsb3MgZGF0b3MgY29tcGxldG9zIGRlIGVzb3MgcGHDrXNlcwp0b3BfY291bnRyaWVzX2RhdGEgPC0gY2FydG9uX2V4cCAlPiUKICBmaWx0ZXIoQ291bnRyeSAlaW4lIHRvcF9jb3VudHJpZXMkQ291bnRyeSkKCiMgQ3JlYXIgZWwgZ3LDoWZpY28KZ2dwbG90KHRvcF9jb3VudHJpZXNfZGF0YSwgYWVzKHggPSByZW9yZGVyKENvdW50cnksIFRyYWRlLlZhbHVlKSwgeSA9IFRyYWRlLlZhbHVlKSkgKwogIGdlb21fY29sKGZpbGwgPSAic3RlZWxibHVlIikgKwogIGNvb3JkX2ZsaXAoKSArICMgSGFjZXIgcXVlIGVsIGdyw6FmaWNvIHNlYSBob3Jpem9udGFsIHBhcmEgbWVqb3IgbGVjdHVyYQogIGxhYnModGl0bGUgPSAiVG9wIDE1IFBhw61zZXMgZW4gVmFsb3IgZGUgRXhwb3J0YWNpw7NuIGRlIENhcnTDs24iLAogICAgICAgeCA9ICJQYcOtcyIsCiAgICAgICB5ID0gIlZhbG9yIGRlIENvbWVyY2lvIChVU0QpIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkKYGBgCgpFbCBhbsOhbGlzaXMgZGUgbGFzIGV4cG9ydGFjaW9uZXMgZ2xvYmFsZXMgZGUgY2FydMOzbiByZXZlbGEgcXVlIE3DqXhpY28gc2UgcG9zaWNpb25hIGNvbW8gdW5vIGRlIGxvcyBsw61kZXJlcyBlbiBlc3RlIHNlY3RvciwgZGVzdGFjw6FuZG9zZSBwb3Igc3VzIHNpZ25pZmljYXRpdm9zIHZhbG9yZXMgZGUgZXhwb3J0YWNpw7NuLiBFc3RhIGZvcnRhbGV6YSBlbiBlbCBtZXJjYWRvIGRlbCBjYXJ0w7NuIHJlZmxlamEgbm8gc29sbyBsYSBhbHRhIGNvbXBldGl0aXZpZGFkIGRlIGxhIGluZHVzdHJpYSBtZXhpY2FuYSwgc2lubyB0YW1iacOpbiBzdSBjYXBhY2lkYWQgcGFyYSBwcm9kdWNpciBtYXRlcmlhbGVzIGRlIGNhbGlkYWQgc3VwZXJpb3IuIFBhcmEgdW5hIGVtcHJlc2EgZW1lcmdlbnRlIGVzcGVjaWFsaXphZGEgZW4gY2FydMOzbiBwYXJhIGF1dG9wYXJ0ZXMsIGVzdG8gcmVwcmVzZW50YSB1bmEgb3BvcnR1bmlkYWQgw7puaWNhIHBhcmEgYXByb3ZlY2hhciBsYSBpbmZyYWVzdHJ1Y3R1cmEgZXhpc3RlbnRlLCBsYXMgZWNvbm9tw61hcyBkZSBlc2NhbGEgeSBsYXMgcmVkZXMgZGUgc3VtaW5pc3RybyBlZmljaWVudGVzIGRlbnRybyBkZSBNw6l4aWNvLiAKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmdncGxvdChjYXJ0b25fZXhwLCBhZXMoeCA9IENvbnRpbmVudCwgeSA9IFRyYWRlLlZhbHVlLkdyb3d0aCAqIDEwMCwgZmlsbCA9IENvbnRpbmVudCkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgNTApLCBicmVha3MgPSBzZXEoMCwgNTAsIDEwKSwgbGFiZWxzID0gcGFzdGUwKHNlcSgwLCA1MCwgMTApLCAiJSIpKSArCiAgbGFicyh0aXRsZSA9ICJDcmVjaW1pZW50byBkZWwgVmFsb3IgZGUgQ29tZXJjaW8gZGUgRXhwb3J0YWNpb25lcyBkZSBDYXJ0w7NuIHBvciBDb250aW5lbnRlIiwKICAgICAgIHggPSAiQ29udGluZW50ZSIsCiAgICAgICB5ID0gIkNyZWNpbWllbnRvIGRlbCBWYWxvciBkZSBDb21lcmNpbyAoJSkiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKRW4gY3VhbnRvIGFsIGNyZWNpbWllbnRvIGRlIGxhIGluZHVzdHJpYSBkZWwgY2FydMOzbiBwb3IgY29udGluZW50ZSwgcG9kZW1vcyB2ZXIgcXVlIE9jZWFuw61hIGVzIGVsIGNvbnRpbmVudGUgY29uIGVsIG1heW9yIHBvcmNlbnRhamUgZGUgY3JlY2ltaWVudG8sIHNpbiBlbWJhcmdvLCBsYSBtZWRpYW5hIGRlbCBjb250aW5lbnRlIG5vcnRlYW1lcmljYW5vIGVzIGRlIHBvY28gbWVub3MgZGVsIDIwJSwgbG8gcXVlIGluZGljYSBxdWUgaGF5IHVuYSB0ZW5kZW5jaWEgcG9zaXRpdmEgZGUgZXN0YSBpbmR1c3RyaWEgZW4gbnVlc3RybyBjb250aW5lbnRlLgoKKkltcG9ydGFjaW9uZXMqCgpgYGB7cn0KIyBGaWx0cmFyIGxvcyAxNSBwYcOtc2VzIGNvbiBtYXlvcmVzIHZhbG9yZXMgZGUgY29tZXJjaW8gZGUgaW1wb3J0YWNpw7NuCgp0b3BfY291bnRyaWVzXzIgPC0gY2FydG9uX2ltcCAlPiUKICBncm91cF9ieShDb3VudHJ5KSAlPiUKICBzdW1tYXJpemUoVG90YWxUcmFkZVZhbHVlID0gc3VtKFRyYWRlLlZhbHVlKSkgJT4lCiAgdG9wX24oMTUsIFRvdGFsVHJhZGVWYWx1ZSkgJT4lCiAgYXJyYW5nZShkZXNjKFRvdGFsVHJhZGVWYWx1ZSkpCgojIFVuaXIgbG9zIGRhdG9zIGZpbHRyYWRvcyBjb24gZWwgZGF0YS5mcmFtZSBvcmlnaW5hbCBwYXJhIG9idGVuZXIgbG9zIGRhdG9zIGNvbXBsZXRvcyBkZSBlc29zIHBhw61zZXMKdG9wX2NvdW50cmllc19kYXRhXzIgPC0gY2FydG9uX2ltcCAlPiUKICBmaWx0ZXIoQ291bnRyeSAlaW4lIHRvcF9jb3VudHJpZXNfMiRDb3VudHJ5KQoKIyBDcmVhciBlbCBncsOhZmljbwpnZ3Bsb3QodG9wX2NvdW50cmllc19kYXRhXzIsIGFlcyh4ID0gcmVvcmRlcihDb3VudHJ5LCBUcmFkZS5WYWx1ZSksIHkgPSBUcmFkZS5WYWx1ZSkpICsKICBnZW9tX2NvbChmaWxsID0gImJsdWUiKSArCiAgY29vcmRfZmxpcCgpICsgCiAgbGFicyh0aXRsZSA9ICJUb3AgMTUgUGHDrXNlcyBlbiBWYWxvciBkZSBJbXBvcnRhY2nDs24gZGUgQ2FydMOzbiIsCiAgICAgICB4ID0gIlBhw61zIiwKICAgICAgIHkgPSAiVmFsb3IgZGUgQ29tZXJjaW8gKFVTRCkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKQpgYGAKRW4gY3VhbnRvIGEgbGFzIGltcG9ydGFjaW9uZXMsIE3DqXhpY28gc2UgY29uc29saWRhIGNvbW8gZWwgY3VhcnRvIG1heW9yIGltcG9ydGFkb3IgbXVuZGlhbCBkZSBjYXJ0w7NuLCBkZXN0YWNhbmRvIHN1IHJvbCBjbGF2ZSBlbiBsYSBpbmR1c3RyaWEgZ2xvYmFsLiBKdXN0byBkZWxhbnRlLCBFc3RhZG9zIFVuaWRvcyBvY3VwYSBsYSBzZWd1bmRhIHBvc2ljacOzbiwgcmVmbGVqYW5kbyBsYSBpbnRlbnNhIGFjdGl2aWRhZCBjb21lcmNpYWwgeSBsYSBkZW1hbmRhIGRlIG1hdGVyaWFsZXMgZGUgY2FsaWRhZCBlbnRyZSBlc3RvcyBwYcOtc2VzIHZlY2lub3MuIEVzdGEgc2l0dWFjacOzbiBzdWJyYXlhIGxhIGltcG9ydGFuY2lhIGVzdHJhdMOpZ2ljYSBkZSBNw6l4aWNvIGVuIGVsIG1lcmNhZG8gZGUgY2FydMOzbiB5IHN1IGNlcmNhbsOtYSBjb24gdW5vIGRlIGxvcyBtYXlvcmVzIGltcG9ydGFkb3JlcywgRXN0YWRvcyBVbmlkb3MsIHBvdGVuY2lhbmRvIGxhcyBvcG9ydHVuaWRhZGVzIGRlIHNpbmVyZ2lhIHkgY29vcGVyYWNpw7NuIHRyYW5zZnJvbnRlcml6YSBlbiBsYSBjYWRlbmEgZGUgc3VtaW5pc3Ryby4KCiMjIyMgSW5kdXN0cmlhIGRlIHZlaMOtY3Vsb3MgZWzDqWN0cmljb3MKCmBgYHtyfQoKIyBDcmVhciB1bmEgbGlzdGEgZGUgZGF0YWZyYW1lcyBwYXJhIGl0ZXJhciAKZWxlY3RyaWNfZGZzIDwtIGxpc3QoZWxlY3RyaWNfMjAxNiA9IGVsZWN0cmljXzIwMTYsIGVsZWN0cmljXzIwMTcgPSBlbGVjdHJpY18yMDE3LAogICAgICAgICAgICAgICAgICAgICBlbGVjdHJpY18yMDE4ID0gZWxlY3RyaWNfMjAxOCwgZWxlY3RyaWNfMjAxOSA9IGVsZWN0cmljXzIwMTksCiAgICAgICAgICAgICAgICAgICAgIGVsZWN0cmljXzIwMjAgPSBlbGVjdHJpY18yMDIwLCBlbGVjdHJpY18yMDIxID0gZWxlY3RyaWNfMjAyMSwKICAgICAgICAgICAgICAgICAgICAgZWxlY3RyaWNfMjAyMiA9IGVsZWN0cmljXzIwMjIsIGVsZWN0cmljXzIwMjMgPSBlbGVjdHJpY18yMDIzKQoKIyBJbmljaWFsaXphciB1biB2ZWN0b3IgcGFyYSBhbG1hY2VuYXIgbG9zIHRvdGFsZXMgZGUgdmVudGFzIGRlIHZlaMOtY3Vsb3MgZWzDqWN0cmljb3MgcG9yIGHDsW8KdG90YWxfc2FsZXNfYnlfeWVhciA8LSBudW1lcmljKGxlbmd0aChlbGVjdHJpY19kZnMpKQpuYW1lcyh0b3RhbF9zYWxlc19ieV95ZWFyKSA8LSBuYW1lcyhlbGVjdHJpY19kZnMpCgojIFN1bWFyIGxhcyB2ZW50YXMgZGUgdmVow61jdWxvcyBlbMOpY3RyaWNvcyBwb3IgYcOxbwpmb3IgKHllYXIgaW4gbmFtZXMoZWxlY3RyaWNfZGZzKSkgewogIHRvdGFsX3NhbGVzX2J5X3llYXJbeWVhcl0gPC0gc3VtKGVsZWN0cmljX2Rmc1tbeWVhcl1dJFZFSF9FTEVDVFIsIG5hLnJtID0gVFJVRSkKfQoKIyBDb252ZXJ0aXIgYSBkYXRhLmZyYW1lCnNhbGVzX2RmIDwtIGRhdGEuZnJhbWUoWWVhciA9IG5hbWVzKHRvdGFsX3NhbGVzX2J5X3llYXIpLCAKICAgICAgICAgICAgICAgICAgICAgICBFbGVjdHJpY1ZlaGljbGVTYWxlcyA9IHRvdGFsX3NhbGVzX2J5X3llYXIpCgojIFZlciBlbCByZXN1bHRhZG8KcHJpbnQoc2FsZXNfZGYpCgojIEFzdW1pZW5kbyBxdWUgc2FsZXNfZGYgeWEgZXN0w6EgY3JlYWRvIHkgY29udGllbmUgbGFzIGNvbHVtbmFzICdZZWFyJyB5ICdFbGVjdHJpY1ZlaGljbGVTYWxlcycKZ2dwbG90KHNhbGVzX2RmLCBhZXMoeCA9IFllYXIsIHkgPSBFbGVjdHJpY1ZlaGljbGVTYWxlcykpICsKICBnZW9tX2NvbChmaWxsID0gInN0ZWVsYmx1ZSIsIGNvbG9yID0gImJsYWNrIikgKyAjIFVzYW1vcyBiYXJyYXMgY29uIGNvbG9yZXMgcGVyc29uYWxpemFkb3MKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gRWxlY3RyaWNWZWhpY2xlU2FsZXMpLCB2anVzdCA9IC0wLjUsIHNpemUgPSAzLjUpICsgIyBBw7FhZGlyIGV0aXF1ZXRhcyBkZSB0ZXh0byBzb2JyZSBsYXMgYmFycmFzCiAgbGFicyh0aXRsZSA9ICJWZW50YXMgZGUgVmVow61jdWxvcyBFbMOpY3RyaWNvcyBlbiBNw6l4aWNvIHBvciBBw7FvIiwKICAgICAgIHN1YnRpdGxlID0gIkRhdG9zIGRlIHZlbnRhcyBkZXNkZSAyMDE2IGhhc3RhIDIwMjMiLAogICAgICAgeCA9ICJBw7FvIiwKICAgICAgIHkgPSAiVmVudGFzIGRlIFZlaMOtY3Vsb3MgRWzDqWN0cmljb3MiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgIyBUZW1hIG1pbmltYWxpc3RhCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwgIyBDZW50cmFyIHkgZGFyIGZvcm1hdG8gYWwgdMOtdHVsbwogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMiksICMgQ2VudHJhciBlbCBzdWJ0w610dWxvCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksICMgRm9ybWF0byBwYXJhIGVsIHTDrXR1bG8gZGVsIGVqZSBYCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksICMgRm9ybWF0byBwYXJhIGVsIHTDrXR1bG8gZGVsIGVqZSBZCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgIyBSb3RhciBsYXMgZXRpcXVldGFzIGRlbCBlamUgWCBwYXJhIG1lam9yYXIgbGEgbGVnaWJpbGlkYWQKCgpgYGAKCkNvbW8gc2UgcHVlZGUgYXByZWNpYXIgZW4gbGEgZ3LDoWZpY2EsIGxhcyB2ZW50YXMgZW4gTcOpeGljbyBkZSBsb3MgdmVow61jdWxvcyBlbMOpY3RyaWNvcyB0aWVuZW4gdW5hIGNsYXJhIHRlbmRlbmNpYSBwb3NpdGl2YSBkZXNkZSBoYWNlIHZhcmlvcyBhw7FvcywgZXN0byByZWZsZWphIGxhIG9wb3J0dW5pZGFkIHkgbGEgbmVjZXNpZGFkIGRlIHF1ZSBlbXByZXNhcyBjb21vIEZPUk0gYWRhcHRlbiBzdSBvZmVydGEgZGUgc29sdWNpb25lcyBhIGxhcyBudWV2YXMgYXV0b3BhcnRlcyBxdWUgcmVxdWllcmVuIGVzdGUgbnVldm8gdGlwbyBkZSB2ZWjDrWN1bG9zLiAKCmBgYHtyfQojU2UgZGV0ZWN0w7MgdW4gZXJyb3IgZW4gSURfRU5USURBRCwgZXhpc3RpZW5kbyBlbCBJRD05OS4gCiMgRmlsdHJhciBwYXJhIGVsaW1pbmFyIElEX0VOVElEQUQgPSA5OQpkYXRvc19maWx0cmFkb3MgPC0gZWxlY3RyaWNfMjAyMyAlPiUKICBmaWx0ZXIoSURfRU5USURBRCAhPSA5OSkKCgoKIyBBZ3J1cGFyIGRhdG9zIHBvciBJRF9FTlRJREFEIHkgc3VtYXIgbGFzIHZlbnRhcyBkZSB2ZWjDrWN1bG9zIGVsw6ljdHJpY29zCnZlbnRhc19wb3JfZXN0YWRvIDwtIGRhdG9zX2ZpbHRyYWRvcyAlPiUKICBncm91cF9ieShJRF9FTlRJREFEKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfVkVIX0VMRUNUUiA9IHN1bShWRUhfRUxFQ1RSLCBuYS5ybSA9IFRSVUUpKQoKZXN0YWRvc19tZXhpY28gPC0gYygiQWd1YXNjYWxpZW50ZXMiLCAiQmFqYSBDYWxpZm9ybmlhIiwgIkJhamEgQ2FsaWZvcm5pYSBTdXIiLCAiQ2FtcGVjaGUiLCAiQ2hpYXBhcyIsCiAgICAgICAgICAgICAgICAgICAgIkNoaWh1YWh1YSIsICJDaXVkYWQgZGUgTcOpeGljbyIsICJDb2FodWlsYSIsICJDb2xpbWEiLCAiRHVyYW5nbyIsICJHdWFuYWp1YXRvIiwKICAgICAgICAgICAgICAgICAgICAiR3VlcnJlcm8iLCAiSGlkYWxnbyIsICJKYWxpc2NvIiwgIk3DqXhpY28iLCAiTWljaG9hY8OhbiIsICJNb3JlbG9zIiwgIk5heWFyaXQiLAogICAgICAgICAgICAgICAgICAgICJOdWV2byBMZcOzbiIsICJPYXhhY2EiLCAiUHVlYmxhIiwgIlF1ZXLDqXRhcm8iLCAiUXVpbnRhbmEgUm9vIiwgIlNhbiBMdWlzIFBvdG9zw60iLAogICAgICAgICAgICAgICAgICAgICJTaW5hbG9hIiwgIlNvbm9yYSIsICJUYWJhc2NvIiwgIlRhbWF1bGlwYXMiLCAiVGxheGNhbGEiLCAiVmVyYWNydXoiLCAiWXVjYXTDoW4iLCAiWmFjYXRlY2FzIikKCmRhdG9zX2ZpbHRyYWRvcyRJRF9FTlRJREFEIDwtIGFzLm51bWVyaWMoZGF0b3NfZmlsdHJhZG9zJElEX0VOVElEQUQpCgojIEFncmVnYXIgdW5hIG51ZXZhIGNvbHVtbmEgY29uIGxvcyBub21icmVzIGRlIGxvcyBlc3RhZG9zCmRhdG9zX2ZpbHRyYWRvcyA8LSBkYXRvc19maWx0cmFkb3MgJT4lCiAgbXV0YXRlKEVzdGFkbyA9IGVzdGFkb3NfbWV4aWNvW0lEX0VOVElEQURdKQoKIyBDcmVhciBsYSBncsOhZmljYQpnZ3Bsb3QodmVudGFzX3Bvcl9lc3RhZG8sIGFlcyh4ID0gZmFjdG9yKElEX0VOVElEQUQpLCB5ID0gVG90YWxfVkVIX0VMRUNUUiwgZmlsbCA9IGZhY3RvcihJRF9FTlRJREFEKSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAiYmxhY2siLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKSArCiAgbGFicyh0aXRsZSA9ICJWZW50YXMgZGUgVmVow61jdWxvcyBFbMOpY3RyaWNvcyBkZSBNw6l4aWNvIHBvciBFc3RhZG8gZW4gMjAyMyIsCiAgICAgICB4ID0gIklEIGRlbCBFc3RhZG8iLAogICAgICAgeSA9ICJUb3RhbCBkZSBWZW50YXMgZGUgVmVow61jdWxvcyBFbMOpY3RyaWNvcyIsCiAgICAgICBjYXB0aW9uID0gIk5vdGE6IElEIGRlbCBFc3RhZG86IDEgPSBBZ3Vhc2NhbGllbnRlcywgZXRjLiBJRF9FTlRJREFEID0gOTkgZXhjbHVpZG8uIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkKYGBgCgpFbiBjdWFudG8gYSBsb3MgZXN0YWRvcyBjb24gbWF5b3JlcyB2ZW50YXMgZGUgdmVow61jdWxvcyBlbMOpY3RyaWNvcyBlbiBlbCDDumx0aW1vIGHDsW8sIGRlc3RhY2FuIGxvcyBlc3RhZG9zIGNvbiBsYXMgY2FwaXRhbGVzIG3DoXMgaW1wb3J0YW50ZXMgZGVsIHBhw61zIGNvbW8gTnVldm8gTGXDs24sIENETVgsIEphbGlzY28sIFF1ZXLDqXRhcm8geSBQdWVibGEuIEVzdG8gcHVlZGUgcmVwcmVzZW50YXIgcGFyYSBGT1JNIG9wb3J0dW5pZGFkZXMgZW4gY3VhbnRvIGEgY8OzbW8gZW5mb2NhciBzdSBjYWRlbmEgZGUgc3VtaW5pc3RybyBwYXJhIGxhcyBtYXlvcmVzIHZlbnRhcyBkZSBzdXMgY2xpZW50ZXMuIAoKIyMjIEZPREEgQ3J1emFkbwpBcGFydGlyIGRlIGxvcyBhbnRlY2VkZW50ZXMgZGUgbGEgZW1wcmVzYSB5IGVsIGNvbnRleHRvIGRlIGxhIGluZHVzdHJpYXMKZGUgTcOpeGljbyB5IEUuVS5BLiBlbGFib3JhciBGT0RBIGNydXphZG8gcXVlIGlkZW50aWZpcXVlIHkgZGVzY3JpYmEgMi0zCmVzdHJhdGVnaWFzIGEgc2VndWlyIHBvciBwYXJ0ZSBkZSBsYSBlbXByZXNhIGVuIGVsIGNvcnRvIHBsYXpvLgoKIyMjIyBGb3J0YWxlemFzOgoxLglFeHBlcnRvcyBlbiBkZXNhcnJvbGxhciBzb2x1Y2lvbmVzIGRlIGVtcGFxdWUgc29zdGVuaWJsZXMgZSBpbm5vdmFkb3JhcyBjb24gdW4gZW5mb3F1ZSBlbiBsYSBpbmR1c3RyaWEgYXV0b21vdHJpeiwgb3B0aW1pemFuZG8gZWwgZXNwYWNpbyBkZSBhbG1hY2VuYW1pZW50bywgYXPDrSBjb21vIGxvcyBjb3N0b3MgbG9nw61zdGljb3MgbG8gcXVlIGluZGljYSB1biBwcm9mdW5kbyBlbnRlbmRpbWllbnRvIGRlIGxhcyBuZWNlc2lkYWRlcyBkZWwgc2VjdG9yIGF1dG9tb3RyaXouCjIuCUFzb2NpYWNpb25lcyBjb24gbWFyY2FzIGRlIGFsdG8gcHJlc3RpZ2lvLCBsYSBlbXByZXNhIGRlIEZvcm0gaGEgZXN0YWJsZWNpZG8gcmVsYWNpb25lcyBjb21lcmNpYWxlcyBjb21vIGxvIGVzIFRlc2xhLCBsbyBxdWUgbm9zIGluZGljYSBsYSBhbHRhIGNhbGlkYWQgeSBjb25maWFiaWxpZGFkIGRlIHN1cyBzb2x1Y2lvbmVzIGRlIGVtcGFxdWUuCjMuCUNvbXByb21pc28gY29uIGxhIHNvc3RlbmliaWxpZGFkLCBsYSBlbXByZXNhIGludGVncmEgcHLDoWN0aWNhcyBzb3N0ZW5pYmxlcyBlbiBzdSBtb2RlbG8gZGUgbmVnb2NpbywgZGVzZGUgcmVkdWNjaW9uZXMgZGUgdXNvIGRlIG1hdGVyaWFsZXMgaGFzdGEgbGEgb3B0aW1pemFjacOzbiBkZSBsb2fDrXN0aWNhLCBxdWUgc2UgYWxpbmVhbiBjb24gbGEgZGVtYW5kYSBhY3R1YWwgZGUgbGEgaW5kdXN0cmlhIGhhY2lhIHByw6FjdGljYXMgbcOhcyBlY29sw7NnaWNhcy4KCiMjIyMgT3BvcnR1bmlkYWRlczoKMS4JQ3JlY2ltaWVudG8gZGVsIG1lcmNhZG8gZW4gbGEgaW5kdXN0cmlhIGNvbiBlbXBhcXVlcyBzb3N0ZW5pYmxlcy4gTGEgY29uY2llbmNpYSBhbWJpZW50YWwgeSByZWd1bGFjaW9uZXMgZGUgbGEgc29zdGVuaWJpbGlkYWQsIHByZXNlbnRhbiB1bmEgZ3JhbiBvcG9ydHVuaWRhZCBwYXJhIGxhIGVtcHJlc2EgZW4gbGlkZXJhciBlbCBkZXNhcnJvbGxvIHkgb2ZlcnRhIGRlIHNvbHVjaW9uZXMgZW4gbG9zIGVtcGFxdWVzIHNvc3RlbmlibGVzLgoyLglEZW1hbmRhIGNyZWNpZW50ZSBkZSBlbXBhcXVlcyBwZXJzb25hbGl6YWRvcyBwYXJhIGxvcyBjbGllbnRlcyBkZWJpZG8gYSBjYW1iaW9zIGVuIGxvcyBjb25zdW1pZG9yZXMuIExhIHRlbmRlbmNpYSBoYWNpYSBzZXJ2aWNpb3MgeSBwcm9kdWN0b3MgcGVyc29uYWxpemFkb3MgcGFyYSBzdXMgY2xpZW50ZXMsIHJlcXVpZXJlIHVuYSBtYXlvciBkZW1hbmRhIGRlIGVtcGFxdWVzIHF1ZSBzZSBhanVzdGVuIGEgbGFzIG5lY2VzaWRhZGVzIGluZGl2aWR1YWxlcyBkZSBzdXMgY2xpZW50ZXMuCjMuCU9wb3J0dW5pZGFkIGRlIGV4cGFuc2nDs24gZW4gaW5kdXN0cmlhcyBmdWVyYSBkZSBsYSBpbmR1c3RyaWEgYXV0b21vdHJpeiBxdWUgcmVxdWllcmVuIGRlIHNvbHVjaW9uZXMgaW5ub3ZhZG9yYXMgZGUgZW1wYXF1ZS4gT3RyYXMgaW5kdXN0cmlhcyB0YW1iacOpbiByZXF1aWVyZW4gZGUgc29sdWNpb25lcyBkZSBlbXBhcXVlIGlubm92YWRvcmFzIGxvIHF1ZSBwcmVzZW50YSB1bmEgb3BvcnR1bmlkYWQgcGFyYSBsYSBlbXByZXNhIGRlIGV4cGFuZGlyIHN1IG1lcmNhZG8gYSBvdHJvcyBzZWN0b3Jlcy4KCiMjIyMgRGViaWxpZGFkZXM6IAoxLglBY3R1YWxtZW50ZSBzZSBlbmN1ZW50cmFuIGVuIHBvdGVuY2lhbCBkZXBlbmRlbmNpYSBkZSBsYSBpbmR1c3RyaWEgYXV0b21vdHJpei4gRXN0byBwb2Ryw61hIHJlcHJlc2VudGFyIHVuIGFsdG8gcmllc2dvIHNpIGVsIHNlY3RvciBsbGVnYXLDoSBhIGVuZnJlbnRhciBkaXNtaW51Y2lvbmVzIGVuIGxhIGRlbWFuZGEgbyBkZXNhZsOtb3MgZWNvbsOzbWljb3MuCjIuCU5lY2VzaWRhZCBlbiBlc3RhciBhY3R1YWxpemFkb3MgY29udGludWFtZW50ZSBmcmVudGUgYSB0ZWNub2xvZ8OtYXMgZW4gZGVzYXJyb2xsbyBkZSBlbXBhcXVlLiBNYW50ZW5lcnNlIGVuIGNvbnN0YW50ZSBpbm5vdmFjacOzbiByZXF1aWVyZSBpbnZlcnNpw7NuIGVuIGludmVzdGlnYWNpb25lcyB5IGRlc2Fycm9sbG8sIGxvIHF1ZSBwdWVkZSBzZXIgdW4gcmV0byBlbiByZWN1cnNvcyB5IGNhcGl0YWwuCjMuCUxpbWl0YWNpb25lcyBlbiBsYSBkaXZlcnNpZmljYWNpw7NuIGRlIHByb2R1Y3Rvcy4gTGEgZXNwZWNpYWxpemFjacOzbiBxdWUgdGllbmVuIHNvYnJlIGxvcyBlbXBhcXVlcyBkZSBhdXRvcGFydGVzIHBvZHLDrWEgbGltaXRhciBsYSBjYXBhY2lkYWQgZGUgbGEgZW1wcmVzYSBwYXJhIGNhcGl0YWxpemFyIHkgZXhwbG9yYXIgb3BvcnR1bmlkYWRlcyBlbiBvdHJvcyBtZXJjYWRvcyB5IHByb2R1Y3Rvcy4KCiMjIyMgQW1lbmF6YXM6IAoxLglDb25zdGFudGUgY2FtYmlvIGVuIGxhcyByZWd1bGFjaW9uZXMgYW1iaWVudGFsZXMgcXVlIHB1ZWRlbiBhZmVjdGFyIGxvcyBtYXRlcmlhbGVzIHBhcmEgcmVhbGl6YXIgbG9zIGVtcGFxdWVzLiBQdWVkZSBoYWJlciB1biBncmFuIGltcGFjdG8gYWwgdXNhciBjaWVydG9zIHByb2Nlc29zIHkgbWF0ZXJpYWxlcyBxdWUgcmVxdWllcmVuIGRlIGFkYXB0YWNpb25lcyBjb3N0b3Nhcy4KMi4JR3JhbiBjb21wZXRlbmNpYSBjcmVjaWVudGUgZW4gZWwgc2VjdG9yIGRlIGVtcGFxdWVzIHNvc3RlbmlibGVzLiBFbCBjcmVjaW1pZW50byBkZSBsYSBpbmR1c3RyaWEgeSBzdSBkZW1hbmRhIGRlIHNvbHVjaW9uZXMgZGUgZW1wYXF1ZXMgc29zdGVuaWJsZXMgYXRyYWUgYSBudWV2b3MgY29tcGV0aWRvcmVzLCBlc3RvIGluY3JlbWVudGEgbGEgcHJlc2nDs24gcGFyYSBsYSBlbXByZXNhIHBvciBkaWZlcmVuY2lhcnNlIHkgY29udGludWFyIGlubm92YW5kby4gCjMuCVZvbGF0aWxpZGFkIGVuIGxvcyBjb3N0b3MgZGUgbWF0ZXJpYWxlcyBkZWJpZG8gYSBmbHVjdHVhY2lvbmVzIGRlbCBtZXJjYWRvLiBFc3RvIHB1ZWRlIGFmZWN0YXIgbG9zIG3DoXJnZW5lcyBkZSBiZW5lZmljaW8geSBsYSBjb21wZXRpdGl2aWRhZCBkZSBwcmVjaW9zIGRlIGxhcyBzb2x1Y2lvbmVzIGRlIEZPUk0uCgojIyMjIEVzdHJhdGVnaWFzOgpFc3RyYXRlZ2lhcyBGT0RBIENydXphZG8gcGFyYSBGT1JNCgojIyMjIyBGb3J0YWxlemFzLU9wb3J0dW5pZGFkZXMgKEZPKQotICoqU29zdGVuaWJpbGlkYWQgZSBJbm5vdmFjacOzbjoqKiBVdGlsaXphciBsYSBleHBlcmllbmNpYSB5IGVsIGNvbXByb21pc28gZGUgbGEgZW1wcmVzYSBjb24gbGEgc29zdGVuaWJpbGlkYWQgcGFyYSBwb2RlciBsaWRlcmFyIGVuIGxhIGluZHVzdHJpYSB5IGVuIGVsIG1lcmNhZG8gY29uIGVtcGFxdWVzIHJlbm92YWJsZXMgeSBlY29sw7NnaWNvcyBwYXJhIHNlZ3VpciBjcmVjaWVuZG8gYW50ZSBsYSBkZW1hbmRhLgotICoqRXhwYW5zacOzbiBlbiBTZXJ2aWNpb3MgUGVyc29uYWxpemFkb3M6KiogRGVzYXJyb2xsYXIgc29sdWNpb25lcyBwZXJzb25hbGl6YWRhcyBhIGxvcyBjbGllbnRlcyB5IG1lam9yYXIgc3UgcmVsYWNpw7NuIGNvbiBtYXJjYXMgZGUgcHJlc3RpZ2lvLgoKIyMjIyMgRGViaWxpZGFkZXMtT3BvcnR1bmlkYWRlcyAoRE8pCi0gKipNaXRpZ2FyIGRlcGVuZGVuY2lhcyBlbiBlbCBtZXJjYWRvOioqIEFtcGxpYXIgZWwgbWVyY2FkbyBoYWNpYSBudWV2YXMgaW5kdXN0cmlhcywgcGFyYSByZWR1Y2lyIGxhIGRlcGVuZGVuY2lhIGRlbCBzZWN0b3IgYXV0b21vdHJpeiwgY3JlY2llbmRvIGEgbnVldm9zIG1lcmNhZG9zIGNvbiBkZW1hbmRhIGNyZWNpZW50ZSBhIHNvbHVjaW9uZXMgaW5ub3ZhZG9yYXMuCi0gKipDb2xhYm9yYWNpb25lcyBjb24gSW5ub3ZhY2nDs246KiogUmVhbGl6YXIgY29sYWJvcmFjaW9uZXMgZXN0cmF0w6lnaWNhcyBwYXJhIGRpdmlkaXIgZWwgY29zdG8gZGUgcmllc2dvIGRlIGlubm92YWNpw7NuIHkgZGVzYXJyb2xsbywgZMOhbmRvbGUgYSBsYSBlbXByZXNhIHVuIGdyYW4gYWxjYW5jZSBwYXJhIHNlciBlbCBsw61kZXIgZW4gbGEgaW5kdXN0cmlhLgoKIyMjIyMgRm9ydGFsZXphcy1BbWVuYXphcyAoRkEpCi0gKipMaWRlcmF6Z28gYW50ZSBDYW1iaW9zIHJlZ3VsYXRvcmlvczoqKiBFbXBsZWFyIGNvbXByb21pc28gY29uIGxhIGlubm92YWNpw7NuIHkgc29zdGVuaWJpbGlkYWQgcGFyYSBxdWUgbGEgZW1wcmVzYSBzZSBhZGFwdGUgYW50ZSBsb3MgY2FtYmlvcyBlbiByZWd1bGFjaW9uZXMgZWNvbMOzZ2ljYXMsIHBvc2ljaW9uYW5kbyBhIEZPUk0gY29tbyB1biByZWZlcmVudGUgZW4gY3VtcGxpbWllbnRvIHkgYWRhcHRhYmlsaWRhZC4KLSAqKlZhbG9yIGFncmVnYWRvIGZyZW50ZSBhIGxhIENvbXBldGVuY2lhOioqIEZvcnRhbGVjZXIgYSBsYSBlbXByZXNhIGEgdHJhdsOpcyBkZSBzdSBjb25maWFiaWxpZGFkIGNvbiBzdXMgY2xpZW50ZXMsIGFwcm92ZWNoYW5kbyBzdSBjYWxpZGFkIHBhcmEgZGVzdGFjYXJzZSBlbiBlbCBtZXJjYWRvIGNvbXBldGl0aXZvLCBhc8OtIG1pc21vIGFwcm92ZWNoYW5kbyBzdXMgY29sYWJvcmFjaW9uZXMgY29uIG1hcmNhcyBkZSBhbHRvIHByZXN0aWdpby4KCiMjIyMjIERlYmlsaWRhZGVzLUFtZW5hemFzIChEQSkKLSAqKkNvYmVydHVyYSBkZSByaWVzZ28gZW4gQ29zdG9zOioqIFJlYWxpemFyIGVzdHJhdGVnaWFzIHBhcmEgdG9tYXIgbWVkaWRhcyBkZSBwcmV2ZW5jacOzbiBwYXJhIHByb3RlZ2Vyc2UgY29udHJhIGxhIHZvbGF0aWxpZGFkIGRlIGxvcyBwcmVjaW9zIGRlIGxvcyBtYXRlcmlhbGVzLCBjb21vIGxvIGVzIGxhIGRpdmVyc2lmaWNhY2nDs24gZGUgbG9zIHByb3ZlZWRvcmVzIHkgbG9zIGNvbnRyYXRvcyBkZSBsYSBlbXByZXNhIGEgbGFyZ28gcGxhem8uCi0gKipQcm9ncmFtYXMgZGUgTGVhbHRhZCBjb24gQ2xpZW50ZXM6KiogSW1wbGVtZW50YXIgcHJvZ3JhbWFzIGRlIGNvbGFib3JhY2nDs24geSBsZWFsdGFkIGNvbiBsb3MgY2xpZW50ZXMgYWN0dWFsZXMsIHBhcmEgcG9kZXIgbWVqb3JhciBsYSByZWxhY2nDs24gYSBsYXJnbyBwbGF6byB5IG1pdGlnYXIgZWwgaW1wYWN0byBkZSBsYSBjb21wZXRlbmNpYSB5IGxhcyBmbHVjdHVhY2lvbmVzIGRlbCBtZXJjYWRvLgoKIyMjIFBFU1RMRQoKQ29uIGJhc2UgZW4gZWwgYW7DoWxpc2lzIGRlIGxhcyBpbmR1c3RyaWFzIGRlIE3DqXhpY28geSBFLlUuQS4gaWRlbnRpZmljYXIKdmFyaWFibGVzIC8gZmFjdG9yZXMgcmVsZXZhbnRlcyBwYXJhIGxhIGVsYWJvcmFjacOzbiBkZSBQRVNUTEUgeQpkZXNjcmliaXIgMi0zIGVzdHJhdGVnaWFzIGEgc2VndWlyIHBvciBwYXJ0ZSBkZSBsYSBlbXByZXNhIGVuIGVsIGNvcnRvCnBsYXpvLgoKIyMjIyBQb2zDrXRpY29zLgoKRUUuVVUuIGFkdmllcnRlIHRlcm1pbmFyIHRyYXRhZG8gZGUgY29tZXJjaW8gY29uIE3DqXhpY28gcG9yIGbDoWJyaWNhcyBkZQpjYXJyb3MgY2hpbm9zLiBMYXMgZnV0dXJhcyBlbGVjY2lvbmVzIHB1ZWRlbiBzZXIgdW4gZmFjdG9yIG11eQppbXBvcnRhbnRlIGVuIGxhIGluZHVzdHJpYSBhdXRvbW90cml6LCB5YSBxdWUgc2Vnw7puIEJCQyBOZXdzLCBUcnVtcCBzZQptdWVzdHJhIGRlIG1hbmVyYSBtdXkgaG9zdGlsIGFudGUgbG9zIGZhYnJpY2FudGVzIGRlIGF1dG9tw7N2aWxlcy4gUG9yIGxvCnF1ZSwgcHVlZGUgcXVlIGltcG9uZ2EgYWxndW5hIGxleSBxdWUgYWZlY3RlIG5lZ2F0aXZhbWVudGUgbGEgaW5kdXN0cmlhLgpFbCBUcmF0YWRvIGVudHJlIE3DqXhpY28sIEVzdGFkb3MgVW5pZG9zIHkgQ2FuYWTDoSAoVC1NRUMpIGVzdGFibGVjZQpyZWdsYXMgcGFyYSBlbCBjb21lcmNpbyBlbnRyZSBsb3MgdHJlcyBwYcOtc2VzLCBpbmNsdXllbmRvIGxhIGluZHVzdHJpYQphdXRvbW90cml6LiBFbCBULU1FQyBoYSBzaWRvIHBvc2l0aXZvIHBhcmEgbGEgaW5kdXN0cmlhIGF1dG9tb3RyaXoKbWV4aWNhbmEsIHlhIHF1ZSBoYSBhdW1lbnRhZG8gbGEgcHJvZHVjY2nDs24geSBsYXMgZXhwb3J0YWNpb25lcy4gRWwKZ29iaWVybm8gbWV4aWNhbm8gaGEgaW1wbGVtZW50YWRvIHVuYSBzZXJpZSBkZSBwb2zDrXRpY2FzIHBhcmEgcHJvbW92ZXIKbGEgaW5kdXN0cmlhIGF1dG9tb3RyaXosIGNvbW8gbGEgY3JlYWNpw7NuIGRlIHVuIGZvbmRvIGRlIGFwb3lvIGEgbGEKaW5kdXN0cmlhIHkgbGEgcmVkdWNjacOzbiBkZSBpbXB1ZXN0b3MgYSBsYSBpbXBvcnRhY2nDs24gZGUgYXV0b3BhcnRlcy4KCiMjIyMgRWNvbsOzbWljb3MuCgpTZWN0b3IgYXV0b21vdHJpeiwgY29uIGxhIG1heW9yIGRlbWFuZGEgZGUgZXNwYWNpb3MgaW5kdXN0cmlhbGVzIHBvcgpOZWFyc2hvcmluZy4gSW5kdXN0cmlhIGF1dG9tb3RyaXogYXVtZW50YSA3LjglIGxhIHByb2R1Y2Npw7NuIGVuIGZlYnJlcm8uCk3DqXhpY28gcmVjaWJpcsOhIDIgbWlsIDMwMCBtZGQgZGUgaW52ZXJzacOzbiBleHRyYW5qZXJhIGVuIGF1dG9wYXJ0ZXMgZW4KMjAyNDogSU5BLiBFbCBuZWFyc2hvcmluZyBwdWVkZSByZWR1Y2lyIGxvcyBjb3N0b3MgZGUgcHJvZHVjY2nDs24gYWwKYXByb3ZlY2hhciBsYSBtYW5vIGRlIG9icmEgbcOhcyBiYXJhdGEgZW4gcGHDrXNlcyBjZXJjYW5vcy4gRXN0byBwdWVkZQptZWpvcmFyIGxhIGNvbXBldGl0aXZpZGFkIGRlIEZPUk0gZW4gZWwgbWVyY2Fkby4gTGEgdGFzYSBkZSBpbnRlcsOpcyBlbgpFc3RhZG9zIFVuaWRvcyBoYSBhdW1lbnRhZG8gZW4gbG9zIMO6bHRpbW9zIGHDsW9zLiBFc3RvIGhhIGVuY2FyZWNpZG8gZWwKY3LDqWRpdG8gcGFyYSBsb3MgY29uc3VtaWRvcmVzLCBsbyBxdWUgcG9kcsOtYSBhZmVjdGFyIGxhIGRlbWFuZGEgZGUKdmVow61jdWxvcy4KCiMjIyMgU29jaWFsZXMuCgpMYSBjbGFzZSBtZWRpYSBlbiBNw6l4aWNvIGVzdMOhIGNyZWNpZW5kby4gRXN0byBoYSBhdW1lbnRhZG8gbGEgZGVtYW5kYSBkZQp2ZWjDrWN1bG9zLCB5YSBxdWUgbGFzIHBlcnNvbmFzIGRlIGxhIGNsYXNlIG1lZGlhIHRpZW5lbiBtw6FzIGRpbmVybyBwYXJhCmdhc3Rhci4gTGFzIHByZW9jdXBhY2lvbmVzIGFtYmllbnRhbGVzIGVzdMOhbiBhdW1lbnRhbmRvIGVuIEVzdGFkb3MKVW5pZG9zLiBFc3RvIHBvZHLDrWEgYWZlY3RhciBsYSBkZW1hbmRhIGRlIHZlaMOtY3Vsb3MsIHlhIHF1ZSBsb3MKY29uc3VtaWRvcmVzIHBvZHLDrWFuIG9wdGFyIHBvciBjb21wcmFyIHZlaMOtY3Vsb3MgbcOhcyBlZmljaWVudGVzIGVuCmNvbWJ1c3RpYmxlIG8gdmVow61jdWxvcyBlbMOpY3RyaWNvcy4KCiMjIyMgVGVjbm9sw7NnaWNvcy4KClNlIGJ1c2NhIHF1ZSBlbiBNw6l4aWNvIHNvbG8gc2UgdmVuZGFuIGF1dG9zIGVsw6ljdHJpY29zLiBQcm90YWdvbmlzdGFzIGRlCmxhIGluZHVzdHJpYSBhdXRvbW90cml6IGVuIE3DqXhpY28gaGFuIHVuaWRvIGZ1ZXJ6YXMgcGFyYSBjcmVhciBsYQpFbGVjdHJvIE1vdmlsaWRhZCBBc29jaWFjacOzbiAoRU1BKSwgYWxpYW56YSBxdWUgbmFjZSBjb24gZWwgb2JqZXRpdm8gZGUKYWxjYW56YXIgZWwgMTAwIHBvciBjaWVudG8gZGUgdmVudGFzIGRlIHZlaMOtY3Vsb3MgZWzDqWN0cmljb3MgcGFyYSBlbCBhw7FvCjIwMzUuCgojIyMjIExlZ2FsZXMuCgpFeHBvcnRhY2nDs24gZGUgYXV0b3MgbWFkZSBpbiBNw6l4aWNvIGNyZWNlIDIyLjYlIGVuIGZlYnJlcm8geSBhY2VsZXJhIGEKbcOheGltbyBoaXN0w7NyaWNvLiBTdGVsbGFudGlzIGFudW5jaWEgaW1wb3J0YW50ZSBwbGFuIGRlIGludmVyc2lvbmVzIHBhcmEKQW3DqXJpY2EgTGF0aW5hLiBMYXMgcmVndWxhY2lvbmVzIGRlIHNlZ3VyaWRhZCBwYXJhIGxvcyB2ZWjDrWN1bG9zIGVzdMOhbgphdW1lbnRhbmRvIGVuIHRvZG8gZWwgbXVuZG8uIEVzdG8gZXN0w6Egb2JsaWdhbmRvIGEgbGFzIGVtcHJlc2FzCmF1dG9tb3RyaWNlcyBhIGludmVydGlyIGVuIG51ZXZhcyB0ZWNub2xvZ8OtYXMgZGUgc2VndXJpZGFkLgoKIyMjIyBFY29sw7NnaWNvcy4KCkxhIEluZHVzdHJpYSBOYWNpb25hbCBkZSBBdXRvcGFydGVzIGFzZWd1csOzIHF1ZSBsYSBwcm9kdWNjacOzbiBkZQpiYXRlcsOtYXMgcGFyYSBhdXRvcyBlbMOpY3RyaWNvcyBlbiBOb3J0ZWFtw6lyaWNhIGVzIGZ1bmRhbWVudGFsIHBhcmEKY3VtcGxpciBjb24gbGFzIHJlZ2xhcyBkZSBvcmlnZW4gZGVsIFQtTUVDLiBFbCBjYW1iaW8gY2xpbcOhdGljbyBlcyB1bmEKcHJlb2N1cGFjacOzbiBpbXBvcnRhbnRlIHBhcmEgbGEgaW5kdXN0cmlhIGF1dG9tb3RyaXouIExhcyBlbXByZXNhcwphdXRvbW90cmljZXMgZXN0w6FuIGRlc2Fycm9sbGFuZG8gdmVow61jdWxvcyBtw6FzIGVmaWNpZW50ZXMgZW4gY29tYnVzdGlibGUKeSB2ZWjDrWN1bG9zIGVsw6ljdHJpY29zIHBhcmEgcmVkdWNpciBzdSBpbXBhY3RvIGFtYmllbnRhbC4KCiMjIERlZmluaWNpw7NuIGRlIFByb2JsZW3DoXRpY2FzCgojIyMgU2l0dWFjacOzbiBQcm9ibGVtYSAxOiBSb3RhY2nDs24gZGUgUGVyc29uYWwKCkV4cGxvcmFyLCBkZWZpbmlyLCB5IGRlc2NyaWJpciBjdcOhbGVzIHNvbiBsb3MgcHJpbmNpcGFsZXMgZmFjdG9yZXMgZGVsIGNsaW1hIG9yZ2FuaXphY2lvbmFsIGRlIEZPUk0gcXVlIHByb3BpY2lhbiBsYSBzYXRpc2ZhY2Npw7NuIHkvbyBubyBzYXRpc2ZhY2Npw7NuIGRlIHRyYWJhamFyIGVuIGRpY2hhIGVtcHJlc2EuCgpMYSByb3RhY2nDs24gZGUgcGVyc29uYWwgc2UgaGEgaWRlbnRpZmljYWRvIGNvbW8gZWwgZGVzYWbDrW8gbcOhcyBjcsOtdGljbyBxdWUgZW5mcmVudGEgRk9STSBlbiBlbCBwcmVzZW50ZS4gQSBwZXNhciBkZSBudWVzdHJvcyBlc2Z1ZXJ6b3MgY29udGludW9zIHBhcmEgY3JlYXIgdW4gYW1iaWVudGUgbGFib3JhbCBhdHJhY3Rpdm8geSByZXRlbmVyIGEgbnVlc3Ryb3MgdmFsaW9zb3MgZW1wbGVhZG9zLCBub3MgZW5jb250cmFtb3MgY29uIHVuYSB0YXNhIGRlIHJvdGFjacOzbiBlc3BlY2lhbG1lbnRlIGFsdGEgZW50cmUgbG9zIG9wZXJhZG9yZXMuIEVzdGUgZmVuw7NtZW5vIG5vIHNvbG8gYWZlY3RhIGxhIGNvbnRpbnVpZGFkIHkgbGEgZWZpY2llbmNpYSBkZSBudWVzdHJhcyBvcGVyYWNpb25lcywgc2lubyBxdWUgdGFtYmnDqW4gaW5jcmVtZW50YSBsb3MgY29zdG9zIGFzb2NpYWRvcyBjb24gZWwgcmVjbHV0YW1pZW50byB5IGxhIGNhcGFjaXRhY2nDs24gZGUgbnVldm8gcGVyc29uYWwuCgotICAgKipQcmluY2lwYWxlcyBQdW50b3M6KioKICAgIC0gICBMYSBlc3RhYmlsaWRhZCBmYW1pbGlhciB5IGxhcyBjb25kaWNpb25lcyBsYWJvcmFsZXMgc29uIGZhY3RvcmVzIHNpZ25pZmljYXRpdm9zIHF1ZSBpbmZsdXllbiBlbiBsYSBkZWNpc2nDs24gZGUgbG9zIGVtcGxlYWRvcyBkZSBwZXJtYW5lY2VyIGVuIGxhIGVtcHJlc2EuCiAgICAtICAgTG9zIGrDs3ZlbmVzLCBlc3BlY2lhbG1lbnRlIGFxdWVsbG9zIHNpbiBjb21wcm9taXNvcyBmYW1pbGlhcmVzLCB0aWVuZGVuIGEgYnVzY2FyIG9wb3J0dW5pZGFkZXMgZGUgZGVzYXJyb2xsbyBwcm9mZXNpb25hbCBmdWVyYSBkZSBGT1JNLgogICAgLSAgIEVzIGNydWNpYWwgbWVqb3JhciBudWVzdHJhcyBlc3RyYXRlZ2lhcyBkZSByZWNsdXRhbWllbnRvIHkgcmV0ZW5jacOzbiBwYXJhIGFib3JkYXIgbGFzIGNhdXNhcyBzdWJ5YWNlbnRlcyBkZSBsYSByb3RhY2nDs24gZGUgcGVyc29uYWwuCgojIyMgU2l0dWFjacOzbiBQcm9ibGVtYSAyOiBQcmVkaWNjacOzbiBkZSBEZW1hbmRhCgpFeHBsb3JhciwgZGVzYXJyb2xsYXIsIHkgZGVzY3JpYmlyIGxhKHMpIHBvc2libGUocykgZXN0cmF0ZWdpYShzKSBkZSBwcmVkaWNjacOzbiBkZSBsYSBkZW1hbmFkYSBkZSBwcm9kdWN0b3MgZmFicmljYWRvcyBwb3IgbGEgZW1wcmVzYSBGT1JNLgoKTGEgcHJlZGljY2nDs24gcHJlY2lzYSBkZSBsYSBkZW1hbmRhIHJlcHJlc2VudGEgdW4gZGVzYWbDrW8gaWd1YWxtZW50ZSBzaWduaWZpY2F0aXZvIHBhcmEgRk9STSwgZGFkYSBsYSB2YXJpYWJpbGlkYWQgaW5oZXJlbnRlIGVuIGxhIHByb2R1Y2Npw7NuIHkgdmVudGEgZGUgYXV0b3BhcnRlcy4gTGEgaGFiaWxpZGFkIHBhcmEgYW50aWNpcGFyIGNvbiBleGFjdGl0dWQgY3XDoW50YXMgdW5pZGFkZXMgZGUgdW4gZGV0ZXJtaW5hZG8gY29tcG9uZW50ZSBzZXLDoW4gbmVjZXNhcmlhcyBlcyBjcnVjaWFsIHBhcmEgb3B0aW1pemFyIG51ZXN0cm9zIHByb2Nlc29zIGRlIHByb2R1Y2Npw7NuIHkgZW1wYXF1ZSwgeSBwYXJhIGFzZWd1cmFyIHF1ZSBzZSBtYXhpbWljZSBsYSBlZmljaWVuY2lhIGVuIGVsIHVzbyBkZSByZWN1cnNvcy4KCi0gICAqKlByaW5jaXBhbGVzIFB1bnRvczoqKgogICAgLSAgIExhIG5hdHVyYWxlemEgZmx1Y3R1YW50ZSBkZSBsYSBkZW1hbmRhIGF1dG9tb3RyaXogY29tcGxpY2EgbGEgcGxhbmlmaWNhY2nDs24geSBnZXN0acOzbiBkZSBpbnZlbnRhcmlvcy4KICAgIC0gICBFcyBlc2VuY2lhbCBkZXNhcnJvbGxhciBoZXJyYW1pZW50YXMgeSBwcm9jZXNvcyBtw6FzIHNvZmlzdGljYWRvcyBwYXJhIG1lam9yYXIgbGEgcHJlY2lzacOzbiBlbiBudWVzdHJhcyBwcmVkaWNjaW9uZXMgZGUgZGVtYW5kYS4KICAgIC0gICBMYSBhZGFwdGFiaWxpZGFkIHkgbGEgY2FwYWNpZGFkIGRlIHJlc3BvbmRlciByw6FwaWRhbWVudGUgYSBsb3MgY2FtYmlvcyBlbiBlbCBtZXJjYWRvIHNvbiBmdW5kYW1lbnRhbGVzIHBhcmEgbWFudGVuZXIgbnVlc3RyYSBjb21wZXRpdGl2aWRhZC4KCiMjIFByZWd1bnRhcyBkZSBBbmFsaXNpcwoKRWxhYm9yYXIgNC02IHByZWd1bnRhcyByZWxhY2lvbmFkYXMgY29uIGxhIHNpdHVhY2nDs24gcHJvYmxlbWEgc2VsZWNjaW9uYWRhIHF1ZSBzZSBwdWVkYW4gcmVzcG9uZGVyIG1lZGlhbnRlIGVsIGFuw6FsaXNpcyBkZSBkYXRvcy4KCioqU2l0dWFjacOzbiBQcm9ibGVtYSAxOiBSb3RhY2nDs24gZGUgUGVyc29uYWwqKgoKLSDCv1F1w6kgZXN0w6EgY2F1c2FuZG8gbGEgcm90YWNpw7NuIGRlIHBlcnNvbmFsIHRhbiBhbHRhPwoKLSDCv0V4aXN0ZSBhbGfDum4gbW9tZW50byBkZWwgYcOxbyBkb25kZSBzZSBkZW4gbcOhcyBiYWphcyBkZW50cm8gZGUgbGEgZW1wcmVzYT8KCi0gwr9Dw7NtbyBzZSBzaWVudGUgbGEgZ2VudGUgZGVudHJvIGRlIHN1IHRyYWJham8gYWN0dWFsPwoKLSDCv1F1w6kgZmFjdG9yIGF5dWRhIGEgcXVlIGVsIHBlcnNvbmFsIGR1cmUgbcOhcyB0aWVtcG8gZGVudHJvIGRlIGxhIGVtcHJlc2E/CgotIMK/RW4gcXXDqSBwYXJ0ZSBkZSBsYSBlbXByZXNhIGVsIHRyYWJhamFkb3Igc2Ugc2llbnRlIG3DoXMgaW5jb25mb3JtZSB5IGN1w6FsIGVzIHN1IHBlcmZpbD8KCiMjIEFuYWxpc2lzIGRlIEV4cGxvcmFjacOzbiBkZSBEYXRvcwoKIyMjIFRyYW5zZm9ybWFjaW9uZXMgTmVjZXNhcmlhcwoKKipGT1JNIEJhamFzKioKYGBge3J9CiMgTGltcGllemEgZGUgRmVjaGEKZm9ybV9iYWphcyRgRmVjaGEgZGUgTmFjaW1pZW50b2AgPC0gYXMuRGF0ZShmb3JtX2JhamFzJGBGZWNoYSBkZSBOYWNpbWllbnRvYCAtIGlmZWxzZShmb3JtX2JhamFzJGBGZWNoYSBkZSBOYWNpbWllbnRvYCA+IDYwLCAxLCAwKSwgb3JpZ2luPSIxODk5LTEyLTMwIikKZm9ybV9iYWphcyRgRmVjaGEgZGUgQWx0YWAgPC0gYXMuRGF0ZShmb3JtX2JhamFzJGBGZWNoYSBkZSBBbHRhYCAtIGlmZWxzZShmb3JtX2JhamFzJGBGZWNoYSBkZSBBbHRhYCA+IDYwLCAxLCAwKSwgb3JpZ2luPSIxODk5LTEyLTMwIikKZm9ybV9iYWphcyRgUHJpbWVyIE1lc2AgPC0gYXMuRGF0ZShmb3JtX2JhamFzJGBQcmltZXIgTWVzYCAtIGlmZWxzZShmb3JtX2JhamFzJGBQcmltZXIgTWVzYCA+IDYwLCAxLCAwKSwgb3JpZ2luPSIxODk5LTEyLTMwIikKZm9ybV9iYWphcyRgQ3VhcnRvIE1lc2AgPC0gYXMuRGF0ZShmb3JtX2JhamFzJGBDdWFydG8gTWVzYCAtIGlmZWxzZShmb3JtX2JhamFzJGBDdWFydG8gTWVzYCA+IDYwLCAxLCAwKSwgb3JpZ2luPSIxODk5LTEyLTMwIikKZm9ybV9iYWphcyRgRmVjaGEgZGUgQmFqYWAgPC0gYXMuRGF0ZShmb3JtX2JhamFzJGBGZWNoYSBkZSBCYWphYCAtIGlmZWxzZShmb3JtX2JhamFzJGBGZWNoYSBkZSBCYWphYCA+IDYwLCAxLCAwKSwgb3JpZ2luPSIxODk5LTEyLTMwIikKCiMgQ2FsY3VsYXIgbGEgYW50aWfDvGVkYWQgY29tbyBsYSBkaWZlcmVuY2lhIGVudHJlIEZlY2hhIGRlIEJhamEgeSBGZWNoYSBkZSBBbHRhCmZvcm1fYmFqYXMkQW50aWd1ZWRhZCA8LSBhYnMoYXMubnVtZXJpYyhmb3JtX2JhamFzJGBGZWNoYSBkZSBCYWphYCAtIGZvcm1fYmFqYXMkYEZlY2hhIGRlIEFsdGFgLCB1bml0cyA9ICJkYXlzIikpCgpoZWFkKGZvcm1fYmFqYXMpCmBgYAoKKipGT1JNIFJIKioKYGBge3J9CiMgQXNlZ3Vyw6FuZG9ub3MgZGUgcXVlIGxhcyBmZWNoYXMgZXN0w6luIGVuIGZvcm1hdG8gYWRlY3VhZG8KZm9ybV9yaCRgRmVjaGEgZGUgbmFjaW1pZW50b2AgPC0gYXMuRGF0ZShmb3JtX3JoJGBGZWNoYSBkZSBuYWNpbWllbnRvYCwgb3JpZ2luID0gIjE4OTktMTItMzAiKQpmb3JtX3JoJGBGZWNoYSBkZSBBbHRhYCA8LSBhcy5EYXRlKGZvcm1fcmgkYEZlY2hhIGRlIEFsdGFgKQpmb3JtX3JoJGBGZWNoYSBkZSBCYWphYCA8LSBhcy5EYXRlKGZvcm1fcmgkYEZlY2hhIGRlIEJhamFgKQoKIyBDYWxjdWxhciBsYSBFZGFkIHkgbGEgRHVyYWNpw7NuIGVuIGVsIHRyYWJham8KZm9ybV9yaCA8LSBmb3JtX3JoICU+JQogIG11dGF0ZSgKICAgIEVkYWQgPSBpbnRlcnZhbChzdGFydCA9IGBGZWNoYSBkZSBuYWNpbWllbnRvYCwgZW5kID0gU3lzLkRhdGUoKSkgJS8lIHllYXJzKDEpLAogICAgRHVyYWNpb24gPSBjYXNlX3doZW4oCiAgICAgIGlzLm5hKGBGZWNoYSBkZSBCYWphYCkgfiBpbnRlcnZhbChzdGFydCA9IGBGZWNoYSBkZSBBbHRhYCwgZW5kID0gU3lzLkRhdGUoKSkgJS8lIGRheXMoMSksCiAgICAgIFRSVUUgfiBpbnRlcnZhbChzdGFydCA9IGBGZWNoYSBkZSBBbHRhYCwgZW5kID0gYEZlY2hhIGRlIEJhamFgKSAlLyUgZGF5cygxKQogICAgKQogICkKCiMgVmVyaWZpY2FyIGxvcyByZXN1bHRhZG9zCmhlYWQoZm9ybV9yaCkKYGBgCgoKKipGT1JNIEJhamFzIEVzcGFjaWFsKioKYGBge3J9CmZvcm1fYmFqYXMkQ1AgPC0gYXMuY2hhcmFjdGVyKGZvcm1fYmFqYXMkQ1ApCmNwX25sJGRfY29kaWdvIDwtIGFzLmNoYXJhY3RlcihjcF9ubCRkX2NvZGlnbykKCnN0YXRzX3Bvcl9jcCA8LSBmb3JtX2JhamFzICU+JQogIGdyb3VwX2J5KENQKSAlPiUKICBzdW1tYXJpemUoCiAgICBDb250ZW9fRW1wbGVhZG9zID0gbigpLAogICAgTWVkaWFuYV9BbnRpZ3VlZGFkID0gbWVkaWFuKEFudGlndWVkYWQsIG5hLnJtID0gVFJVRSksCiAgICAuZ3JvdXBzID0gJ2Ryb3AnCiAgKQoKZm9ybV9iYWphc19lc3BhY2lhbCA8LSBjcF9ubCAlPiUKICBsZWZ0X2pvaW4oc3RhdHNfcG9yX2NwLCBieSA9IGMoImRfY29kaWdvIiA9ICJDUCIpKQoKIyBSZWVtcGxhemFyIE5BIGNvbiAwIGVuIGxhcyBjb2x1bW5hcyBkZSBpbnRlcsOpcwpmb3JtX2JhamFzX2VzcGFjaWFsJENvbnRlb19FbXBsZWFkb3NbaXMubmEoZm9ybV9iYWphc19lc3BhY2lhbCRDb250ZW9fRW1wbGVhZG9zKV0gPC0gMApmb3JtX2JhamFzX2VzcGFjaWFsJE1lZGlhbmFfQW50aWd1ZWRhZFtpcy5uYShmb3JtX2JhamFzX2VzcGFjaWFsJE1lZGlhbmFfQW50aWd1ZWRhZCldIDwtIDAKCmhlYWQoZm9ybV9iYWphc19lc3BhY2lhbCkKYGBgCgoqKkZPUk0gU2F0aXNmYWNjacOzbioqCmBgYHtyfQojIExpc3RhIGRlIGNvbHVtbmFzIGVzcGVjw61maWNhcyBhIHRyYW5zZm9ybWFyCmNvbHVtbmFzX2FfdHJhbnNmb3JtYXIgPC0gYygic2FsYXJpb19idWVubyIsICJwcmVzdGFjaW9uZXNfYnVlbm8iLCAiam9ybmFkYV9ub19leGNlc2l2YSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIm9mcmVjaW1pZW50b19oZXJyYW1pZW50YXMiLCAibm9fbW9sZXN0aWFfdGVtcGVyYXR1cmEiLCAiZXN0cmVzX2Jham8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmYWNpbGlkYWRfdHJhbnNwb3J0ZSIsICJ6b25hX3RyYWJham9fY29tb2RhIiwgInBlcm1hbmVuY2lhX2Zvcm1fZnV0dXJvIikKCiMgQWp1c3RhciBsYSBmdW5jacOzbiBwYXJhIG1hbmVqYXIgZWwgdHlwbyB5IHZhbG9yZXMgaW5lc3BlcmFkb3MKY29kaWZpY2FyX3Jlc3B1ZXN0YXMgPC0gZnVuY3Rpb24ocmVzcHVlc3RhKSB7CiAgIyBDb3JyZWdpciBwb3NpYmxlcyB0eXBvcwogIHJlc3B1ZXN0YSA8LSBnc3ViKCJUb3RhbG1lbmRlIGVuIGRlc2FjdWVyZG8iLCAiVG90YWxtZW50ZSBlbiBkZXNhY3VlcmRvIiwgcmVzcHVlc3RhKQogIAogICMgVXNhciBzd2l0Y2ggcGFyYSBhc2lnbmFyIHZhbG9yZXMgbnVtw6lyaWNvcwogIHN3aXRjaChyZXNwdWVzdGEsCiAgICAgICAgICJUb3RhbG1lbnRlIGVuIGRlc2FjdWVyZG8iID0gMSwKICAgICAgICAgIk1lZGlhbmFtZW50ZSBlbiBkZXNhY3VlcmRvIiA9IDIsCiAgICAgICAgICJOaSBkZSBhY3VlcmRvIG5pIGVuIGRlc2FjdWVyZG8iID0gMywKICAgICAgICAgIk1lZGlhbmFtZW50ZSBkZSBhY3VlcmRvIiA9IDQsCiAgICAgICAgICJUb3RhbG1lbnRlIGRlIGFjdWVyZG8iID0gNSwKICAgICAgICAgTkEpICMgRGV2b2x2ZXIgTkEgcGFyYSBjdWFscXVpZXIgcmVzcHVlc3RhIG5vIHJlY29ub2NpZGEKfQoKIyBBcGxpY2FyIGxhIGNvZGlmaWNhY2nDs24gc29sbyBhIGxhcyBjb2x1bW5hcyBzZWxlY2Npb25hZGFzLCBhc2VndXJhbmRvIHF1ZSB0b2RhcyBsYXMgdHJhbnNmb3JtYWNpb25lcyBzb24gbnVtw6lyaWNhcwpmb3JtX3NhdGlzZmFjY2lvbltjb2x1bW5hc19hX3RyYW5zZm9ybWFyXSA8LSBsYXBwbHkoZm9ybV9zYXRpc2ZhY2Npb25bY29sdW1uYXNfYV90cmFuc2Zvcm1hcl0sIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoc2FwcGx5KHgsIGNvZGlmaWNhcl9yZXNwdWVzdGFzKSkpCgpoZWFkKGZvcm1fc2F0aXNmYWNjaW9uKQpgYGAKCioqRXhwb3J0YWNpw7NuIGRlIFZlaMOtY3Vsb3MgTcOpeGljbyoqCmBgYHtyfQpleHBfdmVoaWN1bG9zJEZlY2hhIDwtIGFzLnllYXJxdHIoZXhwX3ZlaGljdWxvcyRxdWFydGVyLCBmb3JtYXQgPSAiJVktUSVxIikKYGBgCgoqKlZlbnRhIGRlIFZlaMOtY3Vsb3MgTcOpeGljbyoqCmBgYHtyfQp2ZW50YXNfdmVoaWN1bG9zJEZlY2hhIDwtIGFzLnllYXJxdHIocGFzdGUodmVudGFzX3ZlaGljdWxvcyRBTklPLCB2ZW50YXNfdmVoaWN1bG9zJElEX01FUywgIjEiKSwgZm9ybWF0ID0gIiVZICVtICVkIikKYGBgCgojIyMgUHJlZ3VudGFzIGRlIEFuw6FsaXNpcwoKIyMjIyAqKlNpdHVhY2nDs24gUHJvYmxlbWEgMTogUm90YWNpw7NuIGRlIFBlcnNvbmFsKioKCioqwr9RdcOpIGVzdMOhIGNhdXNhbmRvIGxhIHJvdGFjacOzbiBkZSBwZXJzb25hbCB0YW4gYWx0YT8qKgpgYGB7cn0KIyBSZXVuaXIgdG9kYXMgbGFzIGNvbHVtbmFzIGRlIGludGVyw6lzIGVuIGRvcyBjb2x1bW5hczogJ3ByZWd1bnRhJyB5ICdyZXNwdWVzdGEnCmRhdG9zX2xhcmdvcyA8LSBmb3JtX3NhdGlzZmFjY2lvbiAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoc2FsYXJpb19idWVubywgcHJlc3RhY2lvbmVzX2J1ZW5vLCBqb3JuYWRhX25vX2V4Y2VzaXZhLAogICAgICAgICAgICAgICAgICAgICAgICBvZnJlY2ltaWVudG9faGVycmFtaWVudGFzLCBub19tb2xlc3RpYV90ZW1wZXJhdHVyYSwKICAgICAgICAgICAgICAgICAgICAgICAgZXN0cmVzX2Jham8sIGZhY2lsaWRhZF90cmFuc3BvcnRlLCB6b25hX3RyYWJham9fY29tb2RhLAogICAgICAgICAgICAgICAgICAgICAgICBwZXJtYW5lbmNpYV9mb3JtX2Z1dHVybyksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInByZWd1bnRhIiwgdmFsdWVzX3RvID0gInJlc3B1ZXN0YSIpICU+JQogIGdyb3VwX2J5KHByZWd1bnRhLCByZXNwdWVzdGEpICU+JQogIHN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUKICBtdXRhdGUoUGVyY2VudGFnZSA9IG4gLyBzdW0obikpCgojIE9yZGVuYXIgbGFzIHByZWd1bnRhcyBwb3IgZWwgcG9yY2VudGFqZSBkZSAnTXV5IGVuIGNvbnRyYScgcXVlIGNvcnJlc3BvbmRlIGEgbGEgcmVzcHVlc3RhICcxJwpvcmRlbl9wcmVndW50YXMgPC0gZGF0b3NfbGFyZ29zICU+JQogIGZpbHRlcihyZXNwdWVzdGEgPT0gMSkgJT4lCiAgYXJyYW5nZSgoUGVyY2VudGFnZSkpICU+JQogIHB1bGwocHJlZ3VudGEpCgojIENvbnZlcnRpciAncmVzcHVlc3RhJyBhIHVuIGZhY3RvciBjb24gZXRpcXVldGFzIHBhcmEgbGEgbGV5ZW5kYQpkYXRvc19sYXJnb3MkcmVzcHVlc3RhIDwtIGZhY3RvcihkYXRvc19sYXJnb3MkcmVzcHVlc3RhLCBsZXZlbHMgPSAxOjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk11eSBlbiBjb250cmEiLCAiRW4gY29udHJhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5ldXRyYWwiLCAiQSBmYXZvciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNdXkgYSBmYXZvciIpKQoKIyBQYWxldGEgZGUgY29sb3JlcyBwZXJzb25hbGl6YWRhIHBhcmEgbG9zIG5pdmVsZXMgZGUgYWN1ZXJkbwpjb2xvcmVzX3BlcnNvbmFsaXphZG9zIDwtIGMoIiNkNzE5MWMiLCAiI2ZkYWU2MSIsICIjYzhjNmM0IiwgIiNiYmJjYjgiLCAiIzhkOGM4NiIpCgojIEdlbmVyYXIgZWwgZ3LDoWZpY28KZyA8LSBnZ3Bsb3QoZGF0b3NfbGFyZ29zLCBhZXMoeCA9IGZhY3RvcihwcmVndW50YSwgbGV2ZWxzID0gb3JkZW5fcHJlZ3VudGFzKSwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSByZXNwdWVzdGEpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImZpbGwiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3Jlc19wZXJzb25hbGl6YWRvcywgbGFiZWxzID0gbGV2ZWxzKGRhdG9zX2xhcmdvcyRyZXNwdWVzdGEpKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHkgPSAiUG9yY2VudGFqZSIsIHggPSAiIiwgZmlsbCA9ICIiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsICdsaW5lcycpKQoKIyBQYXJhIGd1YXJkYXIgZWwgZ3LDoWZpY28gZW4gdW4gYXJjaGl2bwpnCmBgYAoKYGBge3J9CnN1bW1hcnkoZm9ybV9zYXRpc2ZhY2Npb24pCmBgYAoKCmBgYHtyfQp2YXJpYWJsZXNfY2F0ZWdvcmljYXMgPC0gYygic2FsYXJpb19idWVubyIsICJwcmVzdGFjaW9uZXNfYnVlbm8iLCAiam9ybmFkYV9ub19leGNlc2l2YSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAib2ZyZWNpbWllbnRvX2hlcnJhbWllbnRhcyIsICJub19tb2xlc3RpYV90ZW1wZXJhdHVyYSIsICJlc3RyZXNfYmFqbyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAiZmFjaWxpZGFkX3RyYW5zcG9ydGUiLCAiem9uYV90cmFiYWpvX2NvbW9kYSIsICJwZXJtYW5lbmNpYV9mb3JtX2Z1dHVybyIpCgojIENhbGN1bGFtb3MgbG9zIHBvcmNlbnRhamVzIHBvciBjYXRlZ29yw61hIHBhcmEgY2FkYSB2YXJpYWJsZQpwb3JjZW50YWplc19jYXRlZ29yaWFzIDwtIGZvcm1fc2F0aXNmYWNjaW9uICU+JQogIHNlbGVjdChhbGxfb2YodmFyaWFibGVzX2NhdGVnb3JpY2FzKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBldmVyeXRoaW5nKCksIG5hbWVzX3RvID0gIlZhcmlhYmxlIiwgdmFsdWVzX3RvID0gIlZhbG9yIikgJT4lCiAgZ3JvdXBfYnkoVmFyaWFibGUpICU+JQogIGNvdW50KFZhbG9yKSAlPiUKICBtdXRhdGUoUG9yY2VudGFqZSA9IG4gLyBzdW0obikgKiAxMDApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoLW4pICAjIFNpIG5vIG5lY2VzaXRhcyBsYSBjb2x1bW5hIGRlIGNvbnRlb3MsIHB1ZWRlcyBvbWl0aXJsYS4KCiMgQ29udmVydGlyIGEgdW4gZm9ybWF0byBhbmNobyBlc3BlY8OtZmljbyBwYXJhIGNhZGEgdmFyaWFibGUgeSB2YWxvcgpwb3JjZW50YWplc19hbmNobyA8LSBwb3JjZW50YWplc19jYXRlZ29yaWFzICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBWYWxvciwgdmFsdWVzX2Zyb20gPSBQb3JjZW50YWplLCBuYW1lc19wcmVmaXggPSAiQ2F0ZWdvcmlhXyIpICU+JQogIHNlbGVjdChWYXJpYWJsZSwgc3RhcnRzX3dpdGgoIkNhdGVnb3JpYV8iKSkgJT4lCiAgYXJyYW5nZShWYXJpYWJsZSkKCiMgTW9kaWZpY2Ftb3MgJ3BvcmNlbnRhamVzX2FuY2hvJyBwYXJhIGZvcm1hdGVhciBsb3MgcG9yY2VudGFqZXMKcG9yY2VudGFqZXNfYW5jaG8gPC0gcG9yY2VudGFqZXNfYW5jaG8gJT4lCiAgbXV0YXRlKGFjcm9zcyhzdGFydHNfd2l0aCgiQ2F0ZWdvcmlhXyIpLCB+c3ByaW50ZigiJS4xZiUlIiwgLikpKQoKIyBWZXIgbG9zIHJlc3VsdGFkb3MKcHJpbnQocG9yY2VudGFqZXNfYW5jaG8pCmBgYAoKCioqwr9FeGlzdGUgYWxnw7puIG1vbWVudG8gZGVsIGHDsW8gZG9uZGUgc2UgZGVuIG3DoXMgYmFqYXMgZGVudHJvIGRlIGxhIGVtcHJlc2E/KioKCmBgYHtyfQojIEFncmVnYXIgdW5hIGNvbHVtbmEgcXVlIGluZGlxdWUgZWwgbWVzIGRlIGxhIGZlY2hhIGRlIGJhamEKZm9ybV9iYWphcyRNZXMgPC0gbW9udGgoZm9ybV9iYWphcyRgRmVjaGEgZGUgQmFqYWApCmZvcm1fYmFqYXMkQcOxbyA8LSB5ZWFyKGZvcm1fYmFqYXMkYEZlY2hhIGRlIEJhamFgKQoKIyBBZ3J1cGFyIHBvciBtZXMgeSBnw6luZXJvLCBsdWVnbyBjb250YXIgbGFzIGJhamFzCmJhamFzX3Bvcl9tZXNfZ2VuZXJvIDwtIGZvcm1fYmFqYXMgJT4lCiAgZ3JvdXBfYnkoTWVzLCBHw6luZXJvKSAlPiUKICBzdW1tYXJpc2UoQ29udGVvID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUKICBhcnJhbmdlKE1lcykKCiMgR3JhZmljYXIgbGFzIGJhamFzIHBvciBtZXMgcGFyYSBjYWRhIGfDqW5lcm8KZ2dwbG90KGJhamFzX3Bvcl9tZXNfZ2VuZXJvLCBhZXMoeCA9IE1lcywgeSA9IENvbnRlbywgZ3JvdXAgPSBHw6luZXJvLCBjb2xvciA9IEfDqW5lcm8pKSArCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjEyLCBsYWJlbHMgPSBtb250aC5uYW1lKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkJhamFzIHBvciBNZXMgRGl2aWRpZG8gcG9yIEfDqW5lcm8iLAogICAgICAgeCA9ICJNZXMiLAogICAgICAgeSA9ICJOw7ptZXJvIGRlIEJhamFzIiwKICAgICAgIGNvbG9yID0gIkfDqW5lcm8iKQpgYGAKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIENvbmZpZ3VyYXIgdG1hcCBwYXJhIHF1ZSBpbnRlbnRlIHJlcGFyYXIgYXV0b23DoXRpY2FtZW50ZSBsb3MgcG9sw61nb25vcyBpbnbDoWxpZG9zCnRtYXBfb3B0aW9ucyhjaGVjay5hbmQuZml4ID0gVFJVRSkKCiMgQ2FsY3VsYXIgbG9zIGJyZWFrcyBwYXJhIENvbnRlbyBkZSBFbXBsZWFkb3MgZXhjbHV5ZW5kbyBsb3MgY2Vyb3MKY29udGVvX2VtcGxlYWRvc192YWx1ZXMgPC0gZm9ybV9iYWphc19lc3BhY2lhbCRDb250ZW9fRW1wbGVhZG9zW2Zvcm1fYmFqYXNfZXNwYWNpYWwkQ29udGVvX0VtcGxlYWRvcyA+IDBdCmJyZWFrc19jb250ZW8gPC0gYygtSW5mLCBxdWFudGlsZShjb250ZW9fZW1wbGVhZG9zX3ZhbHVlcywgcHJvYnMgPSBzZXEoMCwgMSwgYnkgPSAwLjI1KSwgbmEucm0gPSBUUlVFKSkKCiMgQ2FsY3VsYXIgbG9zIGJyZWFrcyBwYXJhIE1lZGlhbmEgZGUgQW50aWfDvGVkYWQgZXhjbHV5ZW5kbyBsb3MgY2Vyb3MKYW50aWd1ZWRhZF92YWx1ZXMgPC0gZm9ybV9iYWphc19lc3BhY2lhbCRNZWRpYW5hX0FudGlndWVkYWRbZm9ybV9iYWphc19lc3BhY2lhbCRNZWRpYW5hX0FudGlndWVkYWQgPiAwXQpicmVha3NfYW50aWd1ZWRhZCA8LSBjKC1JbmYsIHF1YW50aWxlKGFudGlndWVkYWRfdmFsdWVzLCBwcm9icyA9IHNlcSgwLCAxLCBieSA9IDAuMjUpLCBuYS5ybSA9IFRSVUUpKQoKIyBNYXBhIHBhcmEgQ29udGVvIGRlIEVtcGxlYWRvcwpjb250ZW9fZW1wbGVhZG9zX21hcCA8LSB0bV9zaGFwZShmb3JtX2JhamFzX2VzcGFjaWFsKSArIAogIHRtX2ZpbGwoIkNvbnRlb19FbXBsZWFkb3MiLCBwYWxldHRlID0gIkJsdWVzIiwgc3R5bGUgPSAiZml4ZWQiLCBicmVha3MgPSBicmVha3NfY29udGVvLCAKICAgICAgICAgIHRpdGxlID0gIkNvbnRlbyBkZSBFbXBsZWFkb3MiLCBuYS5jb2xvciA9ICJ3aGl0ZSIpICsKICB0bV9ib3JkZXJzKCkgKwogIHRtX2xheW91dChmcmFtZSA9IEZBTFNFLCBsZWdlbmQucG9zaXRpb24gPSBjKCJsZWZ0IiwgImJvdHRvbSIpKQoKIyBNYXBhIHBhcmEgTWVkaWFuYSBkZSBBbnRpZ8O8ZWRhZAptZWRpYW5hX2FudGlndWVkYWRfbWFwIDwtIHRtX3NoYXBlKGZvcm1fYmFqYXNfZXNwYWNpYWwpICsgCiAgdG1fZmlsbCgiTWVkaWFuYV9BbnRpZ3VlZGFkIiwgcGFsZXR0ZSA9ICJCdVB1Iiwgc3R5bGUgPSAiZml4ZWQiLCBicmVha3MgPSBicmVha3NfYW50aWd1ZWRhZCwgCiAgICAgICAgICB0aXRsZSA9ICJNZWRpYW5hIGRlIEFudGlnw7xlZGFkIiwgbmEuY29sb3IgPSAid2hpdGUiKSArCiAgdG1fYm9yZGVycygpICsKICB0bV9sYXlvdXQoZnJhbWUgPSBGQUxTRSwgbGVnZW5kLnBvc2l0aW9uID0gYygicmlnaHQiLCAiYm90dG9tIikpCgojIENvbmZpZ3VyYXIgb3BjaW9uZXMgZGUgdG1hcCBwYXJhIGxhIHZpc3VhbGl6YWNpw7NuIGRlIGxvcyBtYXBhcwp0bWFwX21vZGUoInZpZXciKQoKIyBNb3N0cmFyIG1hcGFzIGxhZG8gYSBsYWRvCnRtYXBfYXJyYW5nZShjb250ZW9fZW1wbGVhZG9zX21hcCwgbWVkaWFuYV9hbnRpZ3VlZGFkX21hcCwgbnJvdyA9IDEpCmBgYAoKCioqwr9Dw7NtbyBzZSBzaWVudGUgbGEgZ2VudGUgZGVudHJvIGRlIHN1IHRyYWJham8gYWN0dWFsPyoqCmBgYHtyfQojIEZ1bmNpw7NuIGFqdXN0YWRhIHBhcmEgcHJlcHJvY2VzYXIgdGV4dG8KcHJlcGFyYXJfdGV4dG8gPC0gZnVuY3Rpb24oZGF0b3MsIGNvbHVtbmEpIHsKICBkYXRvcyAlPiUKICAgIHNlbGVjdCghIXN5bShjb2x1bW5hKSkgJT4lCiAgICBtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgYXMuY2hhcmFjdGVyKSkgJT4lCiAgICBtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiBnc3ViKCJcXGQrIiwgIiIsIC4pKSkgJT4lCiAgICB1bm5lc3RfdG9rZW5zKHdvcmQsICEhc3ltKGNvbHVtbmEpKQp9CgojIEZ1bmNpw7NuIGFqdXN0YWRhIHBhcmEgYW7DoWxpc2lzIGRlIHNlbnRpbWllbnRvIHkgd29yZGNsb3VkIGNvbiBjb2xvcmVzIHBlcnNvbmFsaXphZG9zCmFuYWxpemFyX3lfd29yZGNsb3VkIDwtIGZ1bmN0aW9uKGRhdG9zLCBjb2x1bW5hKSB7CiAgdGV4dG9fcHJlcGFyYWRvIDwtIHByZXBhcmFyX3RleHRvKGRhdG9zLCBjb2x1bW5hKQogIAogICMgT2J0ZW5lciBzZW50aW1pZW50bwogIGVtb2Npb25lc19kZiA8LSB0ZXh0b19wcmVwYXJhZG8gJT4lCiAgICBpbm5lcl9qb2luKGdldF9zZW50aW1lbnRzKCJucmMiKSwgYnkgPSAid29yZCIpICU+JQogICAgY291bnQoc2VudGltZW50LCBzb3J0ID0gVFJVRSkgJT4lCiAgICBwcmludCgpCiAgCiAgIyBGaWx0cmFyIHBhbGFicmFzIHBhcmEgZWwgd29yZGNsb3VkIChhcGFyaWNpw7NuIG3DrW5pbWE6IDMgdmVjZXMpCiAgcGFsYWJyYXNfZnJlY3VlbnRlcyA8LSB0ZXh0b19wcmVwYXJhZG8gJT4lCiAgICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkgJT4lCiAgICBmaWx0ZXIobiA+PSAzKQogIAogICMgRGVmaW5pciBwYWxldGEgZGUgY29sb3JlcyBkZSBncmlzIGNsYXJvIGEgbmFyYW5qYQogIGNvbG9yZXNfZ3Jpc19uYXJhbmphIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygiZGFya2dyZXkiLCAib3JhbmdlIikpKDEwMCkKICAKICAjIEdlbmVyYXIgd29yZGNsb3VkIGNvbiBsYSBwYWxldGEgcGVyc29uYWxpemFkYQogIHNldC5zZWVkKDEyMykKICB3b3JkY2xvdWQod29yZHMgPSBwYWxhYnJhc19mcmVjdWVudGVzJHdvcmQsIGZyZXEgPSBwYWxhYnJhc19mcmVjdWVudGVzJG4sIG1pbi5mcmVxID0gMiwKICAgICAgICAgICAgbWF4LndvcmRzID0gMTAwLCByYW5kb20ub3JkZXIgPSBGQUxTRSwgcm90LnBlciA9IDAuMzUsIAogICAgICAgICAgICBjb2xvcnMgPSBjb2xvcmVzX2dyaXNfbmFyYW5qYSkKfQoKYW5hbGl6YXJfeV93b3JkY2xvdWQoZm9ybV9zYXRpc2ZhY2Npb24sICJtb2xlc3RpYXNfcHVlc3RvIikKYGBgCgoqKsK/UXXDqSBmYWN0b3IgYXl1ZGEgYSBxdWUgZWwgcGVyc29uYWwgZHVyZSBtw6FzIHRpZW1wbyBkZW50cm8gZGUgbGEgZW1wcmVzYT8qKgoKYGBge3J9CmdncGxvdChmb3JtX3JoLCBhZXMoeCA9IEVzdGF0dXMsIHkgPSBFZGFkLCBmaWxsID0gRXN0YXR1cykpICsgCiAgZ2VvbV9ib3hwbG90KGNvbG9yID0gImJsYWNrIikgKwogIGdlb21faml0dGVyKHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2Uoaml0dGVyLndpZHRoID0gMC4yLCBkb2RnZS53aWR0aCA9IDAuNzUpLCBzaXplID0gMiwgYWxwaGEgPSAwLjYpICsKICBsYWJzKHRpdGxlID0gIkVkYWQgcG9yIEVzdGF0dXMiLAogICAgICAgeCA9ICJFc3RhdHVzIiwKICAgICAgIHkgPSAiRWRhZCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiUGFzdGVsMSIpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksIAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpLCAKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkKYGBgCgpgYGB7cn0KY29udGVvc19nZW5lcm8gPC0gZm9ybV9yaCAlPiUKICBncm91cF9ieShHw6luZXJvLCBFc3RhdHVzKSAlPiUKICBzdW1tYXJpc2UoQ291bnQgPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpCgojIEFob3JhIGNyZWFtb3MgZWwgZ3LDoWZpY28gZGUgYmFycmFzIGFwaWxhZGFzIGNvbiBsb3MgY29sb3JlcyBlc3BlY2lmaWNhZG9zCmdncGxvdChjb250ZW9zX2dlbmVybywgYWVzKHggPSBHw6luZXJvLCB5ID0gQ291bnQsIGZpbGwgPSBFc3RhdHVzKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZmlsbCIpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiYWN0aXZvIiA9ICIjMDBDREFDIiwgImJhamEiID0gImRhcmtncmV5IikpICsgCiAgbGFicyh0aXRsZSA9ICJQcm9wb3JjacOzbiBkZSBFc3RhdHVzIHBvciBHw6luZXJvIiwKICAgICAgIHggPSAiR8OpbmVybyIsCiAgICAgICB5ID0gIlByb3BvcmNpw7NuIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxKSkKYGBgCgpgYGB7cn0KY29udGVvc19lc3RhZG9fY2l2aWwgPC0gZm9ybV9yaCAlPiUKICBncm91cF9ieShgRXN0YWRvIENpdmlsYCwgRXN0YXR1cykgJT4lCiAgc3VtbWFyaXNlKENvdW50ID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKIyBBaG9yYSBjcmVhbW9zIGVsIGdyw6FmaWNvIGRlIGJhcnJhcyBhcGlsYWRhcyBjb24gbG9zIGNvbG9yZXMgZXNwZWNpZmljYWRvcwpnZ3Bsb3QoY29udGVvc19lc3RhZG9fY2l2aWwsIGFlcyh4ID0gYEVzdGFkbyBDaXZpbGAsIHkgPSBDb3VudCwgZmlsbCA9IEVzdGF0dXMpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsgIyBDb250ZW9zIGFic29sdXRvcwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImFjdGl2byIgPSAibGlnaHRncmVlbiIsICJiYWphIiA9ICJsaWdodGNvcmFsIikpICsgIyBDb2xvcmVzIHBlcnNvbmFsaXphZG9zCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBkZSBQZXJzb25hcyBwb3IgRXN0YWRvIENpdmlsIHkgRXN0YXR1cyIsCiAgICAgICB4ID0gIkVzdGFkbyBDaXZpbCIsCiAgICAgICB5ID0gIlRvdGFsIGRlIFBlcnNvbmFzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgIApgYGAKCgoqKsK/RW4gcXXDqSBwYXJ0ZSBkZSBsYSBlbXByZXNhIGVsIHRyYWJhamFkb3Igc2Ugc2llbnRlIG3DoXMgaW5jb25mb3JtZSB5IGN1w6FsIGVzIHN1IHBlcmZpbD8qKgoKYGBge3J9CiMgR2VuZXJhciBsb3MgZGF0b3MgcGFyYSBsYSB2YXJpYWJsZSAncGVybWFuZW5jaWFfZm9ybV9mdXR1cm8nCmRhdG9zX3Blcm1hbmVuY2lhIDwtIGZvcm1fc2F0aXNmYWNjaW9uICU+JQogIGdyb3VwX2J5KHBlcm1hbmVuY2lhX2Zvcm1fZnV0dXJvKSAlPiUKICBzdW1tYXJpc2UoQ291bnQgPSBuKCkpICU+JQogIG11dGF0ZShQZXJjZW50YWdlID0gQ291bnQgLyBzdW0oQ291bnQpICogMTAwKQoKIyBQYWxldGEgZGUgY29sb3JlcyBwZXJzb25hbGl6YWRhOiByb2pvLCBkb3JhZG8sIHZlcmRlCmNvbG9yZXNfcGVyc29uYWxpemFkb3MgPC0gYygiI2Q3MTkxYyIsICIjZmRhZTYxIiwgIiNmZmZmYmYiLCAiI2E2ZDk2YSIsICIjMWE5NjQxIikKCiMgR3LDoWZpY28gZGUgYmFycmFzIHBhcmEgJ3Blcm1hbmVuY2lhX2Zvcm1fZnV0dXJvJwpnZ3Bsb3QoZGF0b3NfcGVybWFuZW5jaWEsIGFlcyh4ID0gZmFjdG9yKHBlcm1hbmVuY2lhX2Zvcm1fZnV0dXJvLCBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpKSwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBhcy5mYWN0b3IocGVybWFuZW5jaWFfZm9ybV9mdXR1cm8pKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3Jlc19wZXJzb25hbGl6YWRvcykgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiVG90YWxtZW50ZVxuZW4gZGVzYWN1ZXJkbyIsICJNZWRpYW5hbWVudGVcbmVuIGRlc2FjdWVyZG8iLCAiTmkgZGUgYWN1ZXJkb1xubmkgZW4gZGVzYWN1ZXJkbyIsICJNZWRpYW5hbWVudGVcbmRlIGFjdWVyZG8iLCAiVG90YWxtZW50ZVxuZGUgYWN1ZXJkbyIpKSArCiAgeGxhYigiTml2ZWwgZGUgQWN1ZXJkbyBjb24gbGEgUGVybWFuZW5jaWEgYSBGdXR1cm8iKSArCiAgeWxhYigiUG9yY2VudGFqZSIpICsKICBnZ3RpdGxlKCJEaXN0cmlidWNpw7NuIGRlIFJlc3B1ZXN0YXMgcGFyYSAnUGVybWFuZW5jaWEgYSBGdXR1cm8nIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDAuNSwgc2l6ZSA9IDgpLCAKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKYGBge3J9CiMgRmlsdHJhciBwYXJhIG9idGVuZXIgc29sbyBhcXVlbGxvcyBlbiBkZXNhY3VlcmRvIGNvbiBsYSBwZXJtYW5lbmNpYSBhIGZ1dHVybyAodmFsb3IgMSBvIDIpCmRlc2FjdWVyZG9fcGVybWFuZW5jaWEgPC0gZm9ybV9zYXRpc2ZhY2Npb24gJT4lIAogIGZpbHRlcihwZXJtYW5lbmNpYV9mb3JtX2Z1dHVybyAlaW4lIGMoMSwgMikpCgojIFNlbGVjY2lvbmEgc29sbyBsYXMgY29sdW1uYXMgZGUgaW50ZXLDqXMgcGFyYSBlbCBib3hwbG90CmNvbHVtbmFzX2ludGVyZXMgPC0gYygic2FsYXJpb19idWVubyIsICJwcmVzdGFjaW9uZXNfYnVlbm8iLCAiam9ybmFkYV9ub19leGNlc2l2YSIsIAogICAgICAgICAgICAgICAgICAgICAgIm9mcmVjaW1pZW50b19oZXJyYW1pZW50YXMiLCAibm9fbW9sZXN0aWFfdGVtcGVyYXR1cmEiLCAiZXN0cmVzX2Jham8iLCAKICAgICAgICAgICAgICAgICAgICAgICJmYWNpbGlkYWRfdHJhbnNwb3J0ZSIsICJ6b25hX3RyYWJham9fY29tb2RhIikKCiMgQ29udmVydGlyIGRhdG9zIGEgZm9ybWF0byBsYXJnbyBwYXJhIGJveHBsb3RzCmRhdG9zX2xhcmdvcyA8LSBkZXNhY3VlcmRvX3Blcm1hbmVuY2lhICU+JQogIHNlbGVjdChhbGxfb2YoY29sdW1uYXNfaW50ZXJlcykpICU+JQogIHBpdm90X2xvbmdlcigKICAgIGNvbHMgPSBldmVyeXRoaW5nKCksIAogICAgbmFtZXNfdG8gPSAiVmFyaWFibGUiLCAKICAgIHZhbHVlc190byA9ICJQdW50dWFjaW9uIgogICkKCiMgR2VuZXJhciBib3hwbG90IHBhcmEgY2FkYSB2YXJpYWJsZSBzZWxlY2Npb25hZGEKZ2dwbG90KGRhdG9zX2xhcmdvcywgYWVzKHggPSBWYXJpYWJsZSwgeSA9IFB1bnR1YWNpb24sIGZpbGwgPSBWYXJpYWJsZSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIFB1bnR1YWNpb25lcyBwYXJhIEVtcGxlYWRvcyBlbiBEZXNhY3VlcmRvIGNvbiBsYSBQZXJtYW5lbmNpYSIsIAogICAgICAgeSA9ICJQdW50dWFjacOzbiIpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSAgIyBVc2FyIHVuYSBwYWxldGEgZGUgY29sb3JlcyBhZGVjdWFkYSBwYXJhIGRpc3Rpbmd1aXIgdmFyaWFibGVzCmBgYAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZm9ybV9zYXRpc2ZhY2Npb24kZWRhZCA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihmb3JtX3NhdGlzZmFjY2lvbiRlZGFkKSkKZGVzYWN1ZXJkb19wZXJtYW5lbmNpYSA8LSBmb3JtX3NhdGlzZmFjY2lvbiAlPiUKICBmaWx0ZXIocGVybWFuZW5jaWFfZm9ybV9mdXR1cm8gJWluJSBjKDEsIDIpKQoKIyBEaWFncmFtYSBkZSBkaXNwZXJzacOzbiBwYXJhIHZlciBsYSByZWxhY2nDs24gZW50cmUgJ2VkYWQnIHkgJ3BlcnNvbmFzX2RlcGVuZGllbnRlcycKZ2dwbG90KGZvcm1fc2F0aXNmYWNjaW9uLCBhZXMoeCA9IGVkYWQsIHkgPSBwZXJzb25hc19kZXBlbmRpZW50ZXMpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICJsaWdodGdyZXkiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZGVzYWN1ZXJkb19wZXJtYW5lbmNpYSwgYWVzKHggPSBlZGFkLCB5ID0gcGVyc29uYXNfZGVwZW5kaWVudGVzKSwgYWxwaGEgPSAwLjYsIGNvbG9yID0gImJsdWUiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoKSArICMgQXN1bWltb3MgcXVlIGxhIGVkYWQgZXMgbnVtw6lyaWNhIHkgeWEgbm8gaGF5IGV0aXF1ZXRhcyBlc3BlY8OtZmljYXMKICBnZ3RpdGxlKCJDb21wYXJhY2nDs24gZGUgRWRhZCB5IFBlcnNvbmFzIERlcGVuZGllbnRlcyAoRmlsdHJhZG8gcG9yIFBvY2EgUGVybWFuZW5jaWEpIikgKwogIHhsYWIoIkVkYWQiKSArCiAgeWxhYigiUGVyc29uYXMgRGVwZW5kaWVudGVzIikKYGBgCgpgYGB7cn0KIyBGaWx0cmFyIHBhcmEgb2J0ZW5lciBzb2xvIGFxdWVsbG9zIGVuIGRlc2FjdWVyZG8gY29uIGxhIHBlcm1hbmVuY2lhIGEgZnV0dXJvICh2YWxvciAxIG8gMikKZGVzYWN1ZXJkb19wZXJtYW5lbmNpYSA8LSBmb3JtX3NhdGlzZmFjY2lvbiAlPiUgCiAgZmlsdGVyKHBlcm1hbmVuY2lhX2Zvcm1fZnV0dXJvICVpbiUgYygxLCAyKSkKCiMgT2J0ZW5lciBlbCBjb250ZW8gZGUgY2FkYSByYXrDs24gZGUgZW50cmFkYSB5IG9yZGVuYXJsbyBkZSBtYXlvciBhIG1lbm9yCmNvbnRlb19yYXpvbiA8LSBkZXNhY3VlcmRvX3Blcm1hbmVuY2lhICU+JQogIGNvdW50KHJhem9uX2VudHJhZGEpICU+JQogIGFycmFuZ2UoZGVzYyhuKSkKCiMgQ3JlYXIgZWwgZ3LDoWZpY28gZGUgYmFycmFzIGhvcml6b250YWwgY29uIGJhcnJhIG3DoXMgZ3JhbmRlIGFycmliYQpnZ3Bsb3QoY29udGVvX3Jhem9uLCBhZXMoeCA9IHJlb3JkZXIocmF6b25fZW50cmFkYSwgbiksIHkgPSBuLCBmaWxsID0gbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gImxpZ2h0Ymx1ZSIsIGhpZ2ggPSAiZGFya2JsdWUiKSArCiAgbGFicyh5ID0gIlJhesOzbiBkZSBFbnRyYWRhIiwgeCA9ICJDb250ZW8iLCB0aXRsZSA9ICJDb250ZW8gZGUgUmF6w7NuIGRlIEVudHJhZGEgcGFyYSBEZXNhY3VlcmRvIGNvbiBQZXJtYW5lbmNpYSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgY29vcmRfZmxpcCgpICAjIEdpcmFyIGVsIGdyw6FmaWNvIHBhcmEgb3JpZW50YWNpw7NuIGhvcml6b250YWwKYGBgCgoKIyMjIyAqKlNpdHVhY2nDs24gUHJvYmxlbWEgMjogUHJlZGljY2nDs24gZGUgRGVtYW5kYSoqCgoqKsK/Q3XDoWxlcyBzb24gbG9zIHBhdHJvbmVzIGhpc3TDs3JpY29zIGRlIGRlbWFuZGEgZGUgZW1wYXF1ZXMgZGUgY2FydMOzbiBwYXJhIGF1dG9wYXJ0ZXMgZW4gbG9zIG1lcmNhZG9zIG9iamV0aXZvIGRlIGxhIGVtcHJlc2EgRk9STSwgeSBjw7NtbyB2YXLDrWFuIGVzdG9zIHBhdHJvbmVzIHNlZ8O6biBsYSB0ZW1wb3JhZGEsIGVsIHRpcG8gZGUgYXV0b3BhcnRlLCB5IGxhcyByZWdpb25lcyBnZW9ncsOhZmljYXM/KioKCmBgYHtyfQojIEFncnVwYXIgbGFzIHZlbnRhcyBwb3IgY3VhcnRvCnZlbnRhc19wb3JfcXVhcnRlciA8LSB2ZW50YXNfdmVoaWN1bG9zICU+JQogIGdyb3VwX2J5KEZlY2hhKSAlPiUKICBzdW1tYXJpc2UoVkVIX0hJQlJJREFTID0gc3VtKFZFSF9ISUJSSURBUyksIC5ncm91cHMgPSAnZHJvcCcpCgojIEdyw6FmaWNvIHBhcmEgZXhwb3J0YWNpb25lcwpwMSA8LSBnZ3Bsb3QoZXhwX3ZlaGljdWxvcywgYWVzKHggPSBGZWNoYSwgeSA9IHRyYWRlX3ZhbHVlKSkgKwogIGdlb21fbGluZShjb2xvciA9ICJibHVlIikgKwogIGxhYnModGl0bGUgPSAiRXhwb3J0YWNpb25lcyBwb3IgQ3VhcnRvIiwgeSA9ICJWYWxvciBkZSBFeHBvcnRhY2lvbmVzIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBHcsOhZmljbyBwYXJhIHZlbnRhcyBkZSB2ZWjDrWN1bG9zIGjDrWJyaWRvcwpwMiA8LSBnZ3Bsb3QodmVudGFzX3Bvcl9xdWFydGVyLCBhZXMoeCA9IEZlY2hhLCB5ID0gVkVIX0hJQlJJREFTKSkgKwogIGdlb21fbGluZShjb2xvciA9ICJncmVlbiIpICsKICBsYWJzKHRpdGxlID0gIlZlbnRhcyBkZSBWZWjDrWN1bG9zIiwgeSA9ICJOw7ptZXJvIGRlIFZlaMOtY3Vsb3MiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIEFycmVnbGFyIGxvcyBncsOhZmljb3MgbGFkbyBhIGxhZG8gcGFyYSBjb21wYXJhciB2aXN1YWxtZW50ZQpwMSArIHAyICsgcGxvdF9sYXlvdXQoZ3VpZGVzID0gJ2NvbGxlY3QnKSAmIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCmBgYHtyfQojIFByZXBhcmFyIGxvcyBkYXRvcyBwYXJhIGRlc2NvbXBvc2ljacOzbgpleHBfdHMgPC0gdHMoZXhwX3ZlaGljdWxvcyR0cmFkZV92YWx1ZSwgZnJlcXVlbmN5ID0gNCkgIyBGcmVjdWVuY2lhIHRyaW1lc3RyYWwKdmVudGFzX3RzIDwtIHRzKHZlbnRhc19wb3JfcXVhcnRlciRWRUhfSElCUklEQVMsIGZyZXF1ZW5jeSA9IDQpICMgRnJlY3VlbmNpYSB0cmltZXN0cmFsCgojIERlc2NvbXBvc2ljacOzbiBTVEwgZGUgbGFzIGV4cG9ydGFjaW9uZXMKZXhwX2RlY29tcCA8LSBzdGwoZXhwX3RzLCBzLndpbmRvdyA9ICJwZXJpb2RpYyIpCnBsb3QoZXhwX2RlY29tcCkKCiMgRGVzY29tcG9zaWNpw7NuIFNUTCBkZSBsYXMgdmVudGFzIGRlIHZlaMOtY3Vsb3MgaMOtYnJpZG9zCnZlbnRhc19kZWNvbXAgPC0gc3RsKHZlbnRhc190cywgcy53aW5kb3cgPSAicGVyaW9kaWMiKQpwbG90KHZlbnRhc19kZWNvbXApCmBgYAoKKirigaDCv0PDs21vIGltcGFjdGFuIGxvcyBsYW56YW1pZW50b3MgZGUgbnVldm9zIG1vZGVsb3MgZGUgdmVow61jdWxvcyB5IGxhcyB0ZW5kZW5jaWFzIGVuIGxhIGluZHVzdHJpYSBhdXRvbW90cml6IGVuIGxhIGRlbWFuZGEgZGUgZGlmZXJlbnRlcyB0aXBvcyBkZSBlbXBhcXVlcyBkZSBjYXJ0w7NuIHBhcmEgYXV0b3BhcnRlcz8qKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbXhfdmVoaWNsZV9leHBvcnRzX3N1bW1hcnkgPC0gZXhwX3ZlaGljdWxvc190b3RhbCAlPiUKICBncm91cF9ieShBw7FvLCBTZWdtZW50bykgJT4lCiAgc3VtbWFyaXNlKENhbnRpZGFkX1RvdGFsID0gc3VtKENhbnRpZGFkLCBuYS5ybSA9IFRSVUUpKQoKIyBEZWZpbmlyIGxhIHBhbGV0YSBkZSBjb2xvcmVzIHBlcnNvbmFsaXphZGEKY29sb3JlcyA8LSBjKCIjMkQzMjUwIiwgIiM0MzU1ODUiLCAiIzcwNzdBMSIsICIjRjZCMTdBIiwgIiM5RUM4QjkiLCAiI0JFMzE0NCIpCgojIEFzZWd1cmFyc2UgZGUgcXVlIGhheSBzdWZpY2llbnRlcyBjb2xvcmVzIHBhcmEgbG9zIHNlZ21lbnRvcwojIFJlcGV0aXIgbGEgcGFsZXRhIHNpIGhheSBtw6FzIHNlZ21lbnRvcyBxdWUgY29sb3JlcwpuX3NlZ21lbnRvcyA8LSBsZW5ndGgodW5pcXVlKG14X3ZlaGljbGVfZXhwb3J0c19zdW1tYXJ5JFNlZ21lbnRvKSkKaWYgKG5fc2VnbWVudG9zID4gbGVuZ3RoKGNvbG9yZXMpKSB7CiAgY29sb3JlcyA8LSByZXAoY29sb3JlcywgbGVuZ3RoLm91dCA9IG5fc2VnbWVudG9zKQp9CgojIEdyw6FmaWNvIGRlIGzDrW5lYXMgY29uIGxhIHBhbGV0YSBkZSBjb2xvcmVzIHBlcnNvbmFsaXphZGEKZ2dwbG90KG14X3ZlaGljbGVfZXhwb3J0c19zdW1tYXJ5LCBhZXMoeCA9IEHDsW8sIHkgPSBDYW50aWRhZF9Ub3RhbCwgY29sb3IgPSBTZWdtZW50bywgZ3JvdXAgPSBTZWdtZW50bykpICsgCiAgZ2VvbV9saW5lKCkgKyAjIERpYnVqYSBsw61uZWFzCiAgZ2VvbV9wb2ludCgpICsgIyBBw7FhZGUgcHVudG9zIGVuIGNhZGEgZGF0bwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcmVzKSArICMgVXNhIGxhIHBhbGV0YSBkZSBjb2xvcmVzIGRlZmluaWRhCiAgdGhlbWVfbWluaW1hbCgpICsgIyBVc2EgdW4gdGVtYSBtaW5pbWFsaXN0YQogIGxhYnModGl0bGUgPSAiRXZvbHVjacOzbiBkZSBsYSBFeHBvcnRhY2nDs24gZGUgU2VnbWVudG8gZGUgVmVow61jdWxvIGEgbG8gTGFyZ28gZGUgbG9zIEHDsW9zIiwKICAgICAgIHggPSAiQcOxbyIsCiAgICAgICB5ID0gIkNhbnRpZGFkIFRvdGFsIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYAoKKirigaDCv0N1w6FsIGhhIHNpZG8gZWwgZWZlY3RvIGRlIGxhcyBjYW1wYcOxYXMgZGUgbWFya2V0aW5nIHkgbGFzIGFjdGl2aWRhZGVzIHByb21vY2lvbmFsZXMgZGUgbGEgZW1wcmVzYSBGT1JNIHNvYnJlIGxhIGRlbWFuZGEgZGUgc3VzIHByb2R1Y3RvcyBlbiBlbCBwYXNhZG8/KioKCmBgYHtyfQojIFNpbiBJbmZvcm1hY2nDs24gU3VmaWNpZW50ZQpgYGAKCioq4oGgwr9Dw7NtbyBpbXBhY3RhbiBhbGd1bmFzIHZhcmlhYmxlcyBleHRlcm5hcyBkZSBjYXLDoWN0ZXIgbWFjcm9lY29uw7NtaWNvIGEgbGFzIHZlbnRhcyBkZSBsYSBlbXByZXNhPyoqCgpgYGB7cn0KIyBTaW4gSW5mb3JtYWNpw7NuIFN1ZmljaWVudGUKYGBgCgojIyMgUHJvbm9zdGljYXIgZWwgZXZlbnRvIGRlIE5lYXJzaG9yaW5nLgoKIyMjIyBCYXNlcyBkZSBEYXRvcyBkZSBOZWFyc2hvcmluZwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzZXR3ZCgiLi4vZGF0YWJhc2VzL25lYXJzaG9yaW5nIikKZGY9cmVhZC5jc3YoInF1YXJ0ZXJfZWNvbm9taWNfZGF0YS5jc3YiKQoKc3VtbWFyeShkZikKYGBgCgpgYGB7cn0Kc3RyKGRmKQpgYGAKCmBgYHtyfQojIENhbGN1bGFtb3MgZWwgbsO6bWVybyBkZSBOQSBwb3IgY29sdW1uYQpuYXNfcG9yX2NvbHVtbmEgPC0gc2FwcGx5KGRmLCBmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQoKIyBGaWx0cmFtb3MgbGFzIGNvbHVtbmFzIHF1ZSB0aWVuZW4gNyBvIG3DoXMgTkEgcGFyYSBlbGltaW5hcmxhcwpjb2x1bW5hc19wYXJhX2VsaW1pbmFyIDwtIG5hbWVzKG5hc19wb3JfY29sdW1uYVtuYXNfcG9yX2NvbHVtbmEgPj0gN10pCmRmIDwtIGRmICU+JSBzZWxlY3QoLW9uZV9vZihjb2x1bW5hc19wYXJhX2VsaW1pbmFyKSkKCiMgUGFyYSBsYXMgY29sdW1uYXMgcmVzdGFudGVzLCBpbXB1dGFtb3MgbG9zIE5BIGNvbiBsYSBtZWRpYW5hCmRmIDwtIGRmICU+JSBtdXRhdGUoYWNyb3NzKC5jb2xzID0gd2hlcmUofiBzdW0oaXMubmEoLikpIDwgNyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAuZm5zID0gfiBpZmVsc2UoaXMubmEoLiksIG1lZGlhbiguLCBuYS5ybSA9IFRSVUUpLCAuKSkpCmBgYAoKU2UgcmVhbGl6w7MgdW5hIGltcHV0YWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgeSBzZSBlbGltaW5hcm9uIGFxdWVsbGFzIGNvbiBkZW1hc2lhZG9zIHZhbG9yZXMgTkFTIGZhbHRhbnRlcy4gCgoqKkFuYWxpc2lzIGRlIGxhIEJhc2UgZGUgTmVhcnNob3JpbmcqKgoKYGBge3J9CnN1bW1hcnkoZGYpCmBgYAoKYGBge3J9CmRhdGFmPWRmCgpkYXRhMiA8LSBkZiAlPiUgc2VsZWN0KFllYXIsIFF1YXJ0ZXIsIE5ld19GRElfSW5mbG93cykKZGF0YTIkRmVjaGEgPC0gYXMuRGF0ZShwYXN0ZShkYXRhMiRZZWFyLCBkYXRhMiRRdWFydGVyKSwgZm9ybWF0ID0gIiVZICVCIikKCnRpbWVfc2VyaWUgPC0gdHMoZGF0YTIkTmV3X0ZESV9JbmZsb3dzLCBzdGFydCA9IGMoMjAwNiwgMSksIGZyZXF1ZW5jeSA9IDQpCgpwcmludCh0aW1lX3NlcmllKQpgYGAKClNlIGNvbnZpcnRpw7MgbGEgdmFyaWFibGUgZGUgQcOxbyBlbiBlbCBmb3JtYXRvIGFkZWN1YWRvIGRlIGZlY2hhLgoKYGBge3J9CnBsb3QodGltZV9zZXJpZSwgbWFpbiA9ICJJRUQgcXVhcnRlciIsIHhsYWIgPSAiWWVhciBxdWFydGVyIiwgeWxhYiA9ICJJRUQiKQpgYGAKUG9kZW1vcyB2ZXIgcXVlIGVsIGdyw6FmaWNvIHByZXNlbnRhIHVuIGNsYXJvIGNvbXBvbmVudGUgZGUgZXN0YWNpb25hbGlkYWQgeSBwdWVkZSBoYWJlciBjaWVydGEgZXN0YWNpb25hcmllZGFkLCBzaW4gZW1iYXJnbywgc2UgdmUgdW5hIHRlbmRlbmNpYSBhc2NlbmRlbnRlIGEgbG8gbGFyZ28gZGUgdG9kYSBsYSBzZXJpZSBkZSB0aWVtcG8sIHBvciBsbyBxdWUgZXMgbmVjZXNhcmlvIGFwbGljYXIgZGl2ZXJzYXMgcHJ1ZWJhcyBwYXJhIGNvbXByZW5kZXIgbWVqb3IgbnVlc3RyYSBzZXJpZSBkZSB0aWVtcG8uCgpgYGB7cn0KZGVzY29tcG9zZTwtZGVjb21wb3NlKHRpbWVfc2VyaWUpCnBsb3QoZGVzY29tcG9zZSkKYGBgCgpFbiBlbCBncsOhZmljbyBhbnRlcmlvciBwb2RlbW9zIG9ic2VydmFyIHVuYSBsaWdlcmEgdGVuZGVuY2lhIGVuIHRvZGEgbGEgc2VyaWUgdGVtcG9yYWwgY29tbyBzZSBkZXNjcmliacOzIGFudGVyaW9ybWVudGUsIGVzdG8gcG9kcsOtYSBhZmVjdGFyIGxhIHByZXNlbmNpYSBkZSBlc3RhY2lvbmFyaWVkYWQuIFBvciBvdHJvIGxhZG8sIHNlIGV2aWRlbmNpYSBlbCBjb21wb25lbnRlIGVzdGFjaW9uYWwsIHF1ZSBhdW1lbnRhIGVuIGFsZ3Vub3MgdHJpbWVzdHJlcyBkZSBjYWRhIHBlcsOtb2RvLiBFc3RvIHNlIHB1ZWRlIGV4cGxpY2FyIGVuIGVsIGNvbnRleHRvIGRlIGxhIHZhcmlhYmxlIGRlcGVuZGllbnRlIGNvbiBlc3RhY2lvbmFsaWRhZGVzIGVuIGxhIGRlbWFuZGEgZGUgYmllbmVzIHkgc2VydmljaW9zLCBldmVudG9zIGVjb27Ds21pY29zIGNvbW8gZmVyaWFzIGNvbWVyY2lhbGVzIG8gdGVtcG9yYWRhcyBkZSBpbXB1ZXN0b3MuICwgbyBpbmNsdXNvIHBhdHJvbmVzIGVzdGFjaW9uYWxlcyBlbiBsYSBkaXNwb25pYmlsaWRhZCBkZSByZWN1cnNvcyBuYXR1cmFsZXMuIAoKVG9kbyBlc3RvIGhhY2UgcXVlIGVuIGFsZ3VuYXMgcGFydGVzIGRlIGNhZGEgYcOxbyBsYSBJRUQgYXVtZW50ZSB5IGRpc21pbnV5YSBwZXJpw7NkaWNhbWVudGUuIFJlc3BlY3RvIGFsIGNvbXBvbmVudGUgYWxlYXRvcmlvIHJlc2lkdWFsLCBzZSBvYnNlcnZhIGNpZXJ0byBydWlkbyBlbiBsYXMgc2VyaWVzIHRlbXBvcmFsZXMsIGVzcGVjaWFsbWVudGUgZW4gZWwgcGVyw61vZG8gMjAxMy0yMDE1IHkgMjAyMCBhIDIwMjIuIEVzdG8gc2UgZGViZSBhIHZhcmlhY2lvbmVzIGVuIGxhIHNlcmllIHRlbXBvcmFsIHF1ZSBubyBwdWVkZW4gZXhwbGljYXJzZSBjb24gY29tcG9uZW50ZXMgZGUgZXN0YWNpb25hbGlkYWQgbyB0ZW5kZW5jaWFzIGVuIGxhIHNlcmllIHRlbXBvcmFsLiBFc3RvLCBlbiB1biBjb250ZXh0byByZWFsLCBzZSBwdWVkZSBleHBsaWNhciBjb24gZmVuw7NtZW5vcyBjb24gbGFzIHJlZm9ybWFzIGNvbnN0aXR1Y2lvbmFsZXMgZGVsIHByZXNpZGVudGUgRW5yaXF1ZSBQZcOxYSBOaWV0byBlbiAyMDEzIHkgbGEgcGFuZGVtaWEgZGUgQ09WSUQtMTkgYSBwYXJ0aXIgZGUgMjAyMC4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CiMgVGhlIHN0YXRpb25hcml0eSBvZiB0aGUgc2VyaWVzIGlzIGNoZWNrZWQgd2l0aCB0aGUgZm9sbG93aW5nIEFERiB0ZXN0LgphZGYudGVzdCh0aW1lX3NlcmllKQpgYGAKRWwgcmVzdWx0YWRvIGRlIGxhIFBydWViYSBBdW1lbnRhZGEgZGUgRGlja2V5LUZ1bGxlciAoQURGKSBjb24gdW4gdmFsb3IgcCBkZSAwLjAxIChtZW5vciBhIDAuMDUpIGluZGljYSBxdWUgbGEgc2VyaWUgdGVtcG9yYWwg4oCcdGltZV9zZXJpZXPigJ0gZXMgZXN0YWNpb25hcmlhLCBsbyBxdWUgc2lnbmlmaWNhIHF1ZSBubyBtdWVzdHJhIHRlbmRlbmNpYXMgZW4gZWwgdGllbXBvLgoKYGBge3J9CmFjZih0aW1lX3NlcmllLG1haW49IlNpZ25pZmljYW50IEF1dG9jb3JyZWxhdGlvbnMiKSAKYGBgCgpQb2RlbW9zIG9ic2VydmFyIHF1ZSBsYSBzZXJpZSBubyBtdWVzdHJhIGRlIGF1dG9jb3JyZWxhY2nDs24gc2VyaWFsLCB5YSBxdWUgZW4gbG9zIHBlcmlvZG9zIGxhIGZ1bmNpw7NuIGRlIGF1dG9jb3JyZWxhY2nDs24gbm8gZXhjZWRlIGxhcyBsw61uZWFzIGRlIHNpZ25pZmljYW5jaWEuCgojIyMjIE1vZGVsbyBBcm1hIENhbGN1bGFkbwoKYGBge3Igd2FybmluZz1GQUxTRX0Kc3VtbWFyeShhcm1hPC1hcm1hKGRpZmYodGltZV9zZXJpZSkpLG9yZGVyPWMoMSwxKSkKcGxvdChhcm1hKQpgYGAKRXN0b3MgY29lZmljaWVudGVzIGluZGljYW4gdW5hIGNvcnJlbGFjacOzbiBwb3NpdGl2YSBkw6liaWwgY29uIGVsIHZhbG9yIGFudGVyaW9yIHkgdW5hIGNvcnJlbGFjacOzbiBuZWdhdGl2YSBmdWVydGUgY29uIGVsIGVycm9yIGVuIGVsIHBlcsOtb2RvIGFudGVyaW9yLCByZXNwZWN0aXZhbWVudGUuIEFkZW3DoXMsIHNlIGhhIGluY2x1aWRvIHVuIHTDqXJtaW5vIGRlIGludGVyY2VwdGFjacOzbiBjb24gdW4gdmFsb3IgZXN0aW1hZG8gZGUgMTA5LjgwNTAKCkxvcyByZXNpZHVvcyBkZWwgbW9kZWxvIHRpZW5lbiB1bmEgdmFyaWFuemEgZXN0aW1hZGEgKHNpZ21hXjIpIGRlIDQ3NzQ0ODUgeSBsb3MgcmVzdWx0YWRvcyBkZWwgYWp1c3RlIG11ZXN0cmFuIHVuIEFJQyBtdXkgYWx0by4KCiMjIyMgTW9kZWxvIEFyaW1hIGNvbiBMb2cgeSBEaWZmIENhbGN1bGFkbwoKYGBge3Igd2FybmluZz1GQUxTRX0Kc3VtbWFyeShhcmltYTwtQXJpbWEoZGlmZihsb2coKHRpbWVfc2VyaWUpKSksb3JkZXI9YygxLDEsMSkpKSAKcGxvdChhcmltYSkKYGBgCgpFbCBjb2VmaWNpZW50ZSBhdXRvcnJlZ3Jlc2l2byAoQVIxKSBlcyAtMCw2OTc3IHkgZWwgY29lZmljaWVudGUgZGUgbWVkaWEgbcOzdmlsIChNQTEpIGVzIC0xLDAwMDAuIEVzdG9zIGNvZWZpY2llbnRlcyBpbmRpY2FuIHF1ZSBlbCB2YWxvciBhY3R1YWwgZGUgbGEgc2VyaWUgdGVtcG9yYWwgbG9nYXLDrXRtaWNhbWVudGUgZGlmZXJlbmNpYWRhIGVzdMOhIGNvcnJlbGFjaW9uYWRvIG5lZ2F0aXZhbWVudGUgY29uIHN1IHZhbG9yIGFudGVyaW9yIHkgY29uIGVsIGVycm9yIGVuIGVsIHBlcsOtb2RvIGFudGVyaW9yLgoKTGEgdmFyaWFuemEgZXN0aW1hZGEgZGVsIG1vZGVsbyAoc2lnbWFeMikgZXMgMCwwLjU2NTUuIEVsIHZhbG9yIGxvZ2Fyw610bWljbyBkZSB2ZXJvc2ltaWxpdHVkIGVzIC03My44OSwgeSBsb3MgY3JpdGVyaW9zIGRlIGluZm9ybWFjacOzbiwgY29tbyBlbCBBSUMgKEFrYWlrZSBJbmZvcm1hdGlvbiBDcml0ZXJpb24pLCBlbCBBSUMgY29ycmVnaWRvIChBSUNjKSB5IGVsIEJJQyAoQmF5ZXNpYW4gSW5mb3JtYXRpb24gQ3JpdGVyaW9uKSwgaW5kaWNhbiBxdWUgZXN0ZSBtb2RlbG8gcG9kcsOtYSBzZXIgYXByb3BpYWRvIHBhcmEgbGEgc2VyaWUgdGVtcG9yYWwuCgojIyMjIFBydWViYXMgZGUgRGlhZ25vc3RpY28gZW4gbGEgRGF0YQoKKipNb2RlbG8gQXJtYSoqCmBgYHtyfQphcm1hX3Jlc2lkdWFsczwtYXJtYSRyZXNpZHVhbHMKQm94LnRlc3QoYXJtYV9yZXNpZHVhbHMsbGFnPTEsdHlwZT0iTGp1bmctQm94IikKYGBgCgpFbCB2YWxvciBkZSBwIG9idGVuaWRvIGVuIGxhIHBydWViYSBkZSBCb3gtTGp1bmcgKDAsMDcpIGVzIG1heW9yIHF1ZSBlbCB2YWxvciBkZSBwIG3DoXhpbW8gY29tw7pubWVudGUgdXRpbGl6YWRvIHF1ZSBlcyAwLDA1LiBFc3RvIHNpZ25pZmljYSBxdWUgbm8gc2UgZW5jb250csOzIGV2aWRlbmNpYSBzaWduaWZpY2F0aXZhIGRlIGF1dG9jb3JyZWxhY2nDs24gZW4gbG9zIHJlc2lkdW9zLCB5YSBxdWUgZWwgdmFsb3IgcCBlcyBtYXlvciBxdWUgMCwwNSwgbG8gcXVlIHJlc3BhbGRhIGxhIHZhbGlkZXogZGVsIG1vZGVsbyBlbiB0w6lybWlub3MgZGUgYXV0b2NvcnJlbGFjacOzbi4KCmBgYHtyfQojVGVzdGluZyByZXNpZHVhbHMKc3VwcHJlc3NXYXJuaW5ncyh7CmFybWEkcmVzaWR1YWxzIDwtIG5hLm9taXQoYXJtYSRyZXNpZHVhbHMpCmFkZi50ZXN0KGFybWEkcmVzaWR1YWxzKQp9KQpgYGAKRWwgdmFsb3IgZGUgcCBkZSAwLDAxLCBpbmZlcmlvciBhbCB1bWJyYWwgZGUgMCwwNSwgaW5kaWNhIHVuYSBmdWVydGUgZXZpZGVuY2lhIGNvbnRyYSBsYSBoaXDDs3Rlc2lzIG51bGEgZGUgbm8gZXN0YWNpb25hcmllZGFkLiBFc3RvIHNpZ25pZmljYSBxdWUgZXMgcG9jbyBwcm9iYWJsZSBxdWUgbG9zIHJlc2lkdW9zIHNlYW4gbm8gZXN0YWNpb25hcmlvcy4KCgpgYGB7cn0KaGlzdChhcm1hJHJlc2lkdWFscykKYGBgClNlIGFwcmVjaWEgcmVsYXRpdmEgbm9ybWFsaWRhZCBlbiBsb3MgcmVzaWR1YWxlcy4KCioqTW9kZWxvIEFyaW1hKioKYGBge3J9CmFyaW1hX3Jlc2lkdWFsczwtYXJpbWEkcmVzaWR1YWxzCkJveC50ZXN0KGFyaW1hX3Jlc2lkdWFscyxsYWc9MSx0eXBlPSJManVuZy1Cb3giKQpgYGAKCkVsIHZhbG9yIGRlIHAgb2J0ZW5pZG8gZW4gbGEgcHJ1ZWJhIGRlIEJveC1ManVuZyAoMCw4KSBlcyBtYXlvciBxdWUgZWwgdmFsb3IgZGUgcCBtw6F4aW1vIGNvbcO6bm1lbnRlIHV0aWxpemFkbyBxdWUgZXMgMCwwNS4gRXN0byBzaWduaWZpY2EgcXVlIG5vIHNlIGVuY29udHLDsyBldmlkZW5jaWEgc2lnbmlmaWNhdGl2YSBkZSBhdXRvY29ycmVsYWNpw7NuIGVuIGxvcyByZXNpZHVvcywgeWEgcXVlIGVsIHZhbG9yIHAgZXMgbWF5b3IgcXVlIDAsMDUsIGxvIHF1ZSByZXNwYWxkYSBsYSB2YWxpZGV6IGRlbCBtb2RlbG8gZW4gdMOpcm1pbm9zIGRlIGF1dG9jb3JyZWxhY2nDs24uCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyZXNpZHVhbHNfdHMgPC0gYXJpbWEkcmVzaWR1YWxzCgojIEludGVycG9sYXIgbG9zIHZhbG9yZXMgTkEKcmVzaWR1YWxzX2NsZWFuIDwtIG5hLmFwcHJveChyZXNpZHVhbHNfdHMpCgpzdXBwcmVzc1dhcm5pbmdzKHsKICBhZGZfdGVzdF9yZXN1bHQgPC0gYWRmLnRlc3QocmVzaWR1YWxzX2NsZWFuKQp9KQoKIyBWZXIgZWwgcmVzdWx0YWRvCnByaW50KGFkZl90ZXN0X3Jlc3VsdCkKYGBgCkVsIHZhbG9yIGRlIHAgZGUgMCwwMSwgaW5mZXJpb3IgYWwgdW1icmFsIGRlIDAsMDUsIGluZGljYSB1bmEgZnVlcnRlIGV2aWRlbmNpYSBjb250cmEgbGEgaGlww7N0ZXNpcyBudWxhIGRlIG5vIGVzdGFjaW9uYXJpZWRhZC4gRXN0byBzaWduaWZpY2EgcXVlIGVzIHBvY28gcHJvYmFibGUgcXVlIGxvcyByZXNpZHVvcyBzZWFuIG5vIGVzdGFjaW9uYXJpb3MuCgpgYGB7cn0KaGlzdChhcmltYSRyZXNpZHVhbHMpCmBgYAoKU2UgYXByZWNpYSBub3JtYWxpZGFkIGVuIGxvcyByZXNpZHVhbGVzIGRlbCBtb2RlbG8gMi4KCkRlYmlkbyBhIG3DqXRyaWNhcyBjb21vIGVsIEFJQyB5IGEgbGFzIHBydWViYXMgZGUgZGlhZ27Ds3N0aWNvLCBlbCBtb2RlbG8gMiBlcyBlbGVnaWRvIGNvbW8gZWwgbcOhcyBhcHJvcGlhZG8uCgojIyMjIEZvcmVjYXN0IGRlIE5lYXJzaG9yaW5nCgpgYGB7cn0Kc3VwcHJlc3NXYXJuaW5ncyh7CmFyaW1hX3Jlc3RhdXJhY2lvbjwtZXhwKGFyaW1hJGZpdHRlZCkgIyBUaGUgdmFyaWFibGVzIGFyZSB0cmFuc2Zvcm1lZCBiYWNrIHRvIHRoZSBvcmlnaW5hbHMgKGlmIGxvZyBpcyBhcHBsaWVkLCB0aGUgZXhwb25lbnRpYWwgbXVzdCBiZSBhcHBsaWVkIChpdCBpcyB0aGUgb3Bwb3NpdGUpKQp2ZWN0b3IyID1jKGFyaW1hX3Jlc3RhdXJhY2lvbikgI3JldmVydGluZyAibG9nIiBvcGVyYXRpb24gdXNpbmcgImV4cCIKb3JpZ2luYWwyIDwtYyh0aW1lX3NlcmllKSAjQ29udmVydGluZyBpbnRvIGEgdmVjdG9yLgpyZXN0YXVyYWNpb24yID0gdmVjdG9yMitvcmlnaW5hbDIgI3JldmVydGluZyAiZGlmZiIgb3BlcmF0aW9uIHN1bW1pbmcgdGhlIG9yaWdpbmFsIHZhbHVlcyB0byB0aGUgZGlmZmVyZW5jZXMuCnRzMiA8LSB0cyhyZXN0YXVyYWNpb24yLCBzdGFydCA9IDEsIGVuZCA9IGxlbmd0aChyZXN0YXVyYWNpb24yKSwgZnJlcXVlbmN5ID0gNCkgI01ha2UgdGltZSBzZXJpZXMKfSkKYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQojIEZvcmVjYXN0IChBUklNQSkKYXJpbWFfZm9yZWNhc3Q8LWZvcmVjYXN0KHRzMixoPTUpCmFyaW1hX2ZvcmVjYXN0CnBsb3QoYXJpbWFfZm9yZWNhc3QpCmF1dG9wbG90KGFyaW1hX2ZvcmVjYXN0KQpgYGAKCkVuIGVsIHByb27Ds3N0aWNvIHJlYWxpemFkbyBwYXJhIGxhIEludmVyc2nDs24gRXh0cmFuamVyYSBEaXJlY3RhIChJRUQpIHJlbGFjaW9uYWRhIGNvbiBlbCBmZW7Ds21lbm8gZGVsIG5lYXJzaG9yaW5nLCBzZSBvYnNlcnZhbiB0ZW5kZW5jaWFzIHkgdmFyaWFjaW9uZXMgaW50ZXJlc2FudGVzIHBhcmEgbG9zIHByw7N4aW1vcyBjaW5jbyB0cmltZXN0cmVzLiBMYSBwcmVkaWNjacOzbiBzZSBwcmVzZW50YSBjb24gaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgZGVsIDgwJSB5IGRlbCA5NSUsIGxvIHF1ZSBub3MgcGVybWl0ZSBlbnRlbmRlciBsYSBpbmNlcnRpZHVtYnJlIGFzb2NpYWRhIGNvbiBjYWRhIGVzdGltYWNpw7NuIGRlIHB1bnRvLgoKUGFyYSBlbCBjdWFydG8gdHJpbWVzdHJlIGRlbCBhw7FvIDI0LCBlbCBwcm9uw7NzdGljbyBkZSBwdW50byBlc3RpbWEgdW5hIElFRCBkZSAzLDAzNi4wNjQgbWlsbG9uZXMgZGUgZMOzbGFyZXMuIExvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSBzdWdpZXJlbiBxdWUsIGNvbiB1biA4MCUgZGUgY29uZmlhbnphLCBsYSBJRUQgcG9kcsOtYSB2YXJpYXIgZW50cmUgMSwxMjEuOTg2IHkgNCw5NTAuMTQzIG1pbGxvbmVzIGRlIGTDs2xhcmVzLiBBbXBsaWFuZG8gbGEgY2VydGV6YSBhbCA5NSUsIGVsIHJhbmdvIHNlIGV4dGllbmRlIGRlc2RlIDEwOC43MzQgaGFzdGEgNSw5NjMuMzk0IG1pbGxvbmVzIGRlIGTDs2xhcmVzLCBpbmRpY2FuZG8gdW5hIG1heW9yIGluY2VydGlkdW1icmUgZW4gbGFzIGVzdGltYWNpb25lcy4KCkVuIGVsIHByaW1lciB0cmltZXN0cmUgZGVsIGHDsW8gMjUsIHNlIGVzcGVyYSB1biBhdW1lbnRvIGVuIGxhIElFRCBoYXN0YSBsb3MgMyw3NDIuNTQ3IG1pbGxvbmVzIGRlIGTDs2xhcmVzLiBFbCBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGRlbCA4MCUgc2Ugc2l0w7phIGVudHJlIDEsMzgzLjA2OCB5IDYsMTAyLjAyNiBtaWxsb25lcyBkZSBkw7NsYXJlcywgbWllbnRyYXMgcXVlIGVsIGludGVydmFsbyBhbCA5NSUgc2UgYW1wbMOtYSBkZXNkZSAxMzQuMDM2IGhhc3RhIDcsMzUxLjA1OCBtaWxsb25lcyBkZSBkw7NsYXJlcywgcmVmbGVqYW5kbyBudWV2YW1lbnRlIGxhIGluY2VydGlkdW1icmUgZW4gZWwgcHJvbsOzc3RpY28uCgpQYXJhIGVsIHNlZ3VuZG8gdHJpbWVzdHJlIGRlbCBhw7FvIDI1LCBlbCBwcm9uw7NzdGljbyBtdWVzdHJhIHVuYSBkaXNtaW51Y2nDs24gZW4gbGEgSUVEIGEgMiwzMTguNDEyIG1pbGxvbmVzIGRlIGTDs2xhcmVzLiBMb3MgaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgcGFyYSBlc3RlIHRyaW1lc3RyZSBzb24gbcOhcyBlc3RyZWNob3MsIGNvbiBlbCBpbnRlcnZhbG8gZGVsIDgwJSB2YXJpYW5kbyBlbnRyZSA4NTYuNzc1IHkgMyw3ODAuMDQ5IG1pbGxvbmVzIGRlIGTDs2xhcmVzLCB5IGVsIGRlbCA5NSUgZW50cmUgODMuMDMyIHkgNCw1NTMuNzkzIG1pbGxvbmVzIGRlIGTDs2xhcmVzLgoKRW4gZWwgdGVyY2VyIHRyaW1lc3RyZSBkZWwgYcOxbyAyNSwgc2UgcHJldsOpIHVuIHJlcHVudGUgZW4gbGEgSUVEIGEgMywxMjguNjA0IG1pbGxvbmVzIGRlIGTDs2xhcmVzLCBjb24gaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgc2ltaWxhcmVzIGEgbG9zIG9ic2VydmFkb3MgZW4gZWwgY3VhcnRvIHRyaW1lc3RyZSBkZWwgYcOxbyAyNC4KCkZpbmFsbWVudGUsIHBhcmEgZWwgY3VhcnRvIHRyaW1lc3RyZSBkZWwgYcOxbyAyNSwgZWwgcHJvbsOzc3RpY28gdnVlbHZlIGEgZXN0aW1hciB1bmEgSUVEIGRlIDMsMDM2LjA2NCBtaWxsb25lcyBkZSBkw7NsYXJlcywgY29uIGludGVydmFsb3MgZGUgY29uZmlhbnphIHByw6FjdGljYW1lbnRlIGlkw6ludGljb3MgYSBsb3MgZGVsIGN1YXJ0byB0cmltZXN0cmUgZGVsIGHDsW8gMjQuCgpFc3RlIGFuw6FsaXNpcyBkZSBwcm9uw7NzdGljbyBtdWVzdHJhIHVuYSB2YXJpYWJpbGlkYWQgc2lnbmlmaWNhdGl2YSBlbiBsYSBJRUQgZXNwZXJhZGEgcmVsYWNpb25hZGEgY29uIGVsIG5lYXJzaG9yaW5nIGEgbG8gbGFyZ28gZGUgbG9zIHByw7N4aW1vcyBjaW5jbyB0cmltZXN0cmVzLiAKCiMjIFByaW5jaXBhbGVzIEhhbGxhemdvcwoKIyMjIEluY3JlbWVudG8gZGUgTmVhcnNob3JpbmcKLSAqKlByZXZpc2nDs24gcG9zaXRpdmEqKjogTGEgdGVuZGVuY2lhIGNyZWNpZW50ZSBkZWwgbmVhcnNob3JpbmcgZXMgZXNwZXJhZGEgcGFyYSBpbXB1bHNhciBmYXZvcmFibGVtZW50ZSBsYXMgdmVudGFzIGRlIEZPUk0sIHNlZ8O6biBlbCBtb2RlbG8gQVJJTUEgcXVlIHByb25vc3RpY2EgbGEgSW52ZXJzacOzbiBFeHRyYW5qZXJhIERpcmVjdGEuCgojIyMgVGVuZGVuY2lhcyBlbiBJbmR1c3RyaWFzIENsYXZlCi0gKipBdXRvbW90cml6IHkgQ2FydMOzbioqOiBBbWJhcyBpbmR1c3RyaWFzIG11ZXN0cmFuIHRlbmRlbmNpYXMgcG9zaXRpdmFzLiBMYXMgdmVudGFzIHkgZXhwb3J0YWNpb25lcyBuYWNpb25hbGVzIHJlZmxlamFuIHVuIGluY3JlbWVudG8gY29uc3RhbnRlLCBjb24gbGEgaW5kdXN0cmlhIGF1dG9tb3RyaXogZXhoaWJpZW5kbyBlc3RhY2lvbmFsaWRhZCBjb24gcGljb3MgZW4gZWwgdGVyY2VyIHRyaW1lc3RyZSwgbG8gcXVlIHN1Z2llcmUgdW5hIGNvcnJlbGFjacOzbiBkaXJlY3RhIGVudHJlIHZlbnRhcyB5IGV4cG9ydGFjaW9uZXMuIEVzdG8gcHJlc2VudGEgdW5hIHBlcnNwZWN0aXZhIG9wdGltaXN0YSBwYXJhIGxhIGRlbWFuZGEgZGUgcHJvZHVjdG9zIGRlIEZPUk0uCgojIyMgRmFjdG9yZXMgZGUgUm90YWNpw7NuIGRlIFBlcnNvbmFsCi0gKipQcmluY2lwYWxlcyBjYXVzYW50ZXMgZGUgYmFqYSoqOiBMYSB1YmljYWNpw7NuIGRlIGxhIGVtcHJlc2EsIGFsdGFzIHRlbXBlcmF0dXJhcyB5IGxhIGluc3VmaWNpZW5jaWEgZGUgaGVycmFtaWVudGFzIHNvbiBpZGVudGlmaWNhZG9zIGNvbW8gZmFjdG9yZXMgY3LDrXRpY29zIGRldHLDoXMgZGUgbGEgYmFqYSBkZSBjb2xhYm9yYWRvcmVzLiBFc3BlY8OtZmljYW1lbnRlLCBsYXMgbW9sZXN0aWFzIHBvciB0ZW1wZXJhdHVyYSBhZmVjdGFuIGFsIDMzJSBkZSBsb3MgZW5jdWVzdGFkb3MsIHNlZ3VpZG8gZGUgdW4gMjAlIGVuIGRlc2FjdWVyZG8gY29uIGxhcyBwcmVzdGFjaW9uZXMgeSB1biAxOSUgcXVlIHNlw7FhbGEgbGEgZmFsdGEgZGUgaGVycmFtaWVudGFzIGFkZWN1YWRhcy4KLSAqKkFuw6FsaXNpcyBkZSBQZXJtYW5lbmNpYSoqOiBMYSBkZXRlcm1pbmFjacOzbiBkZSBmYWN0b3JlcyByZWxhY2lvbmFkb3MgY29uIGxhIGJhamEgaW50ZW5jacOzbiBkZSBwZXJtYW5lbmNpYSBlbiBGT1JNIG11ZXN0cmEgcXVlIGVsIG9mcmVjaW1pZW50byBkZSBoZXJyYW1pZW50YXMgYWRlY3VhZGFzIHkgY29uZGljaW9uZXMgZGUgdHJhYmFqbyDDs3B0aW1hcyBzb24gw6FyZWFzIGNsYXZlIGRlIG1lam9yYS4KLSAqKlBlcmZpbCBkZWwgdHJhYmFqYWRvciBpbnNhdGlzZmVjaG8qKjogTWVub3JlcyBkZSAzMCBhw7FvcyBjb24gaGFzdGEgZG9zIHBlcnNvbmFzIGRlcGVuZGllbnRlcywgY2l0YW5kbyBsYSB1YmljYWNpw7NuIGRlIGxhIGVtcHJlc2EgY29tbyBsYSByYXrDs24gcHJpbmNpcGFsIGRlIGVudHJhZGEuCgojIyMgRGVtYW5kYSBkZSBBdXRvcGFydGVzIHkgRW1wYXF1ZXMKLSAqKlZlaMOtY3Vsb3MgRWzDqWN0cmljb3MqKjogTGEgdGVuZGVuY2lhIGFsIGFsemEgZW4gbGEgdmVudGEgZGUgdmVow61jdWxvcyBlbMOpY3RyaWNvcyBzdWdpZXJlIGxhIG5lY2VzaWRhZCBkZSBhZGFwdGFyIGxvcyB0aXBvcyBkZSBlbXBhcXVlcyBwYXJhIGVzdGFzIGF1dG9wYXJ0ZXMsIHJlcHJlc2VudGFuZG8gdW5hIG9wb3J0dW5pZGFkIGRlIGlubm92YWNpw7NuIHBhcmEgRk9STS4KCiMjIyBUZW5kZW5jaWFzIGRlIEJhamFzIGRlIFBlcnNvbmFsCi0gKipJbmNyZW1lbnRvIHkgZ8OpbmVybyoqOiBIYXkgdW4gaW5jcmVtZW50byBub3RhYmxlIGVuIGxhcyBiYWphcyBlbiBjb21wYXJhY2nDs24gY29uIGVsIGHDsW8gYW50ZXJpb3IsIGNvbiB1bmEgbWF5b3IgaW5jaWRlbmNpYSBlbiBtdWplcmVzLiBBZGVtw6FzLCBzZSBvYnNlcnZhIHVuIGF1bWVudG8gZW4gbGFzIGJhamFzIGNvbmZvcm1lIGF2YW56YSBlbCBhw7FvLCBlc3BlY2lhbG1lbnRlIGVuIGFicmlsIHkgZmVicmVyby4KCiMjIyBJbnNpZ2h0cyBBZGljaW9uYWxlcwotIExhIHJlYWxpemFjacOzbiBkZSBlbmN1ZXN0YXMgcG9yIHBhcnRlIGRlIEZPUk0gaGEgcGVybWl0aWRvIGlkZW50aWZpY2FyIGNvbiBwcmVjaXNpw7NuIGxvcyBmYWN0b3JlcyBkZSBzYXRpc2ZhY2Npw7NuIGUgaW5zYXRpc2ZhY2Npw7NuIGxhYm9yYWwsIHN1YnJheWFuZG8gbGEgaW1wb3J0YW5jaWEgZGUgYXRlbmRlciBlc3RhcyDDoXJlYXMgcGFyYSBtZWpvcmFyIGxhIHJldGVuY2nDs24gZGVsIHBlcnNvbmFsLgoKIyMgUmVmZXJlbmNpYXMgCgoxLiAqRCZCIEhvb3ZlcnMgaXMgWW91ciBTYWxlcyBBY2NlbGVyYXRvciAtLSBEdW4gJiBCcmFkc3RyZWV0Ki4gKHMuIGYuKS4gUmVjdXBlcmFkbyAxNiBkZSBtYXJ6byBkZSAyMDI0LCBkZSA8aHR0cHM6Ly93d3cuZG5iLmNvbS9wcm9kdWN0cy9kbmItaG9vdmVycy5odG1sPiAKCjIuICpXb3JsZCBCYW5rIEdyb3VwIC0gSW50ZXJuYXRpb25hbCBEZXZlbG9wbWVudCwgUG92ZXJ0eSwgJiBTdXN0YWluYWJpbGl0eSouIChzLiBmLikuIFdvcmxkIEJhbmsuIFJlY3VwZXJhZG8gMTYgZGUgbWFyem8gZGUgMjAyNCwgZGUgPGh0dHBzOi8vd3d3LndvcmxkYmFuay5vcmcvZW4vaG9tZT4gCgozLiAqU21pdGhlcnMgLSBJbm5vdmF0ZSB3aXRoIGNvbmZpZGVuY2UqLiAocy4gZi4pLiBTbWl0aGVycy4gUmVjdXBlcmFkbyAxNiBkZSBtYXJ6byBkZSAyMDI0LCBkZSA8aHR0cHM6Ly93d3cuc21pdGhlcnMuY29tL2hvbWU+IAoKNC4gKlN0YXRpc3RhLiAocy4gZi4pLiBTdGF0aXN0YSAtIHRoZSBzdGF0aXN0aWNzIHBvcnRhbCouIFJlY3VwZXJhZG8gMTYgZGUgbWFyem8gZGUgMjAyNCwgZGUgPGh0dHBzOi8vd3d3LnN0YXRpc3RhLmNvbS8+IAoKNS4gKk1leGljb0luZHVzdHJ5LiAocy4gZi4pLiAqSW5jcmVtZW50YXLDoSA4JSBlbCBzZWN0b3IgYXV0b21vdHJpeiBlbiAyMDI0Ki4gTWV4aWNvSW5kdXN0cnkuIFJlY3VwZXJhZG8gMTYgZGUgbWFyem8gZGUgMjAyNCwgZGUgPGh0dHBzOi8vbWV4aWNvaW5kdXN0cnkuY29tL25vdGljaWEvaW5jcmVtZW50YXJhLTgtZWwtc2VjdG9yLWF1dG9tb3RyaXotZW4tMjAyND4gCgo2LiAqTmV3c3Jvb20gSW5mb2JhZS4gKDIwMjMsIDEyIGFicmlsKS4gSW5kdXN0cmlhIGF1dG9tb3RyaXogZW4gTcOpeGljbyBlc3BlcmEgbcOhcyBlbXBsZW9zIHBvciBlbGVjdHJvbW92aWxpZGFkLiAqSW5mb2JhZSouIFJlY3VwZXJhZG8gMTYgZGUgbWFyem8gZGUgMjAyNCwgZGUgPGh0dHBzOi8vd3d3LmluZm9iYWUuY29tL2FtZXJpY2EvYWdlbmNpYXMvMjAyMy8wNC8xMi9pbmR1c3RyaWEtYXV0b21vdHJpei1lbi1tZXhpY28tZXNwZXJhLW1hcy1lbXBsZW9zLXBvci1lbGVjdHJvbW92aWxpZGFkLz4KCg==